package com.yanqu.road.server.manager.activity.fivehero;

import com.google.protobuf.AbstractMessage;
import com.yanqu.road.entity.activity.ActivityConditionInfo;
import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.fivehero.FiveHeroConfig;
import com.yanqu.road.entity.activity.fivehero.config.FiveHeroCityConfig;
import com.yanqu.road.entity.activity.fivehero.config.FiveHeroEventConfig;
import com.yanqu.road.entity.activity.fivehero.config.FiveHeroOrderConfig;
import com.yanqu.road.entity.activity.fivehero.config.FiveHeroTypeConfig;
import com.yanqu.road.entity.activity.fivehero.cross.*;
import com.yanqu.road.entity.activity.fivehero.log.LogFiveHeroToken;
import com.yanqu.road.entity.config.battle.BattleResult;
import com.yanqu.road.entity.config.battle.PatronsBattleDetail;
import com.yanqu.road.entity.config.goods.GoodsInfo;
import com.yanqu.road.entity.config.patrons.PatronsInfo;
import com.yanqu.road.entity.enums.activity.fivehero.eFiveHeroEventType;
import com.yanqu.road.entity.enums.activity.fivehero.eFiveHeroRedDotType;
import com.yanqu.road.entity.enums.eGamePlayerEventType;
import com.yanqu.road.entity.enums.eMessageType;
import com.yanqu.road.entity.enums.eUnionPosition;
import com.yanqu.road.entity.log.cross.fivehero.*;
import com.yanqu.road.entity.player.UserBaseInfo;
import com.yanqu.road.entity.union.UnionBaseInfo;
import com.yanqu.road.logic.activity.fivehero.logic.FiveHeroMapLogic;
import com.yanqu.road.logic.bussiness.activity.FiveHeroBusiness;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.logic.helper.ActivityHelper;
import com.yanqu.road.logic.pb.BattlePb;
import com.yanqu.road.logic.pb.PlayerBasePb;
import com.yanqu.road.logic.pb.UnionBasePb;
import com.yanqu.road.message.YanQuMessage;
import com.yanqu.road.pb.activity.FiveHeroProto;
import com.yanqu.road.pb.cross.activity.CrossActivityProto;
import com.yanqu.road.pb.worldmessage.WorldMessageProto;
import com.yanqu.road.server.logic.MessageHelper;
import com.yanqu.road.server.manager.activity.ActivityInfoMgr;
import com.yanqu.road.server.manager.activity.fivehero.logic.CrossFiveHeroChatLogic;
import com.yanqu.road.server.manager.config.GoodsMgr;
import com.yanqu.road.server.manager.config.PatronsMgr;
import com.yanqu.road.server.manager.log.CrossActivityLogMgr;
import com.yanqu.road.server.manager.log.CrossAutoLogMgr;
import com.yanqu.road.server.manager.scene.CrossSceneMgr;
import com.yanqu.road.server.manager.user.CrossUserMgr;
import com.yanqu.road.server.manger.ServerLanguageMgr;
import com.yanqu.road.server.protocol.ClientProtocol;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.GameProtocol;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.YanQuMessageUtils;
import com.yanqu.road.utils.config.Config;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class CrossFiveHeroMatch {

    protected int userMaxRankConfig;
    protected int unionMaxRankConfig;
    protected int campMaxRankConfig;

    private static RandomHelper randomHelper = new RandomHelper();

    private int groupId;

    private Logger logger = LogManager.getLogger(CrossFiveHeroMatch.class.getName());

    // 聊天
    private CrossFiveHeroChatLogic chatLogic;

    private FiveHeroConfig config;

    private List<Long> inEnterUserIdList = new ArrayList<>();

    //在哪个城市，进来的时候是哪个阵营在这个城市 缓存
    private Map<Integer,Map<Long,Integer>> cityBattleUserIdMap = new ConcurrentHashMap<>();

    //玩家的最大击杀数，还要大于这个才有走马灯
    private Map<Long,Map<Integer,Integer>> userTopKillMap = new ConcurrentHashMap<>();
    //玩家的最大城主令，还要大于这个才有走马灯
    private Map<Long,Integer> userTopTokenMap = new ConcurrentHashMap<>();

    /**
     * 大锁
     */
    protected final Object lock = new Object();

    //普通城市打城市，主城打战令，普通城市打山贼
    protected final Map<Integer,Object> cityPvpLockMap = new ConcurrentHashMap<>();
    protected final Map<Integer,Object> cityTokenLockMap = new ConcurrentHashMap<>();
    protected final Map<Integer,Object> cityBanditLockMap = new ConcurrentHashMap<>();

    private CrossFiveHeroMatchData crossFiveHeroMatchData;

    private Map<String, CrossFiveHeroUnion> unionMap = new ConcurrentHashMap<>();

    private Map<Long, CrossFiveHeroUserData> userDataMap = new ConcurrentHashMap<>();

    private Map<Long, List<CrossFiveHeroUserReport>> userReportMap = new ConcurrentHashMap<>();

    private List<CrossFiveHeroCityReport> cityReportList = new ArrayList<>();
    private List<CrossFiveHeroCityReport> cityReportLuoYangList = new ArrayList<>();


    private CrossFiveHeroRankListModel userRank = new CrossFiveHeroRankListModel(); // 个人榜
    private Map<Integer, CrossFiveHeroRankListModel> campUserRankMap = new ConcurrentHashMap(); // 阵营内个人榜
    private Map<Integer, CrossFiveHeroRankListModel> campUnionRankMap = new ConcurrentHashMap<>(); // 阵营内商会榜

    private List<CrossFiveHeroHorseLamp> lampList = new ArrayList<>();
    private List<CrossFiveHeroHorseLamp> needSyncLampList = new ArrayList<>();

    private List<Integer> needSyncCityList = new ArrayList<>();

    private List<CrossFiveHeroCity> needInsertCityDataList = new ArrayList<>();
    private List<CrossFiveHeroCity> needUpdateCityDataList = new ArrayList<>();

    private List<CrossFiveHeroUserReport> needInsertUserReportDataList = new ArrayList<>();
    private List<CrossFiveHeroCityReport> needInsertCityReportDataList = new ArrayList<>();

    private CrossFiveHeroActivity fhAc;

    //洛阳开战的推送时间 时间,每日三次。。。
    private List<Long> luoYangBattleHorseTimeList = new ArrayList<>();

    public void putFiveHeroActivity(CrossFiveHeroActivity ac) {
        fhAc = ac;
    }


    public List<Long> getInMap(){
        return inEnterUserIdList;
    }

    public void addNeedInsertUserReportData(CrossFiveHeroUserReport data){
        synchronized (needInsertUserReportDataList){
            if(!needInsertUserReportDataList.contains(data)){
                needInsertUserReportDataList.add(data);
            }
        }
    }

    public void aaa(String a){

    }

    public void offLineUser(List<Long> userIdList) {
        synchronized (inEnterUserIdList){
            for(long userId : userIdList){
                inEnterUserIdList.remove(userId);
                for(Integer cityId : cityBattleUserIdMap.keySet()){
                    Map<Long,Integer> aMap = cityBattleUserIdMap.get(cityId);
                    if(aMap.containsKey(userId)){
                        aMap.remove(userId);
                        addCityChange(cityId);
                    }
                }
            }
        }
    }

    //判断玩家在线不在线
    private void checkUserOnCity(){
        if(inEnterUserIdList.contains(null)){
            synchronized (inEnterUserIdList){
                List<Long> newList = new ArrayList<>();
                for(Long userId : inEnterUserIdList){
                    if(userId != null){
                        newList.add(userId);
                    }
                }
                inEnterUserIdList = newList;
            }
        }

        List<Long> userIdList = new ArrayList<>(inEnterUserIdList);
        Map<Long,List<Long>> serverIdUserIdMap = new ConcurrentHashMap<>();
        for(long userId : userIdList){
            UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(userId);
            if(userBaseInfo != null){
                if(!serverIdUserIdMap.containsKey(userBaseInfo.getServerId())){
                    serverIdUserIdMap.put(userBaseInfo.getServerId(),new ArrayList<>());
                }
                serverIdUserIdMap.get(userBaseInfo.getServerId()).add(userId);
            }
        }
        for(long serverId : serverIdUserIdMap.keySet()){
            FiveHeroProto.FiveHeroCheckUserOnlineMsg.Builder checkMsg = FiveHeroProto.FiveHeroCheckUserOnlineMsg.newBuilder();
            checkMsg.addAllUserId(serverIdUserIdMap.get(serverId));
            checkMsg.setActivityId(getActivityInfo().getActivityId());
            checkMsg.setGroupId(groupId);
            MessageHelper.sendPacket(serverId, 0, YanQuMessageUtils.buildMessage(GameProtocol.S_FIVEHERO_CHECK_USER_ONLINE, checkMsg));
        }
    }

    //是不是大于历史最大击杀数，大于才跑走马灯
    private boolean isTopKill(long userId,int cityType,int killCount){
        if(!userTopKillMap.containsKey(userId)){
            userTopKillMap.put(userId,new ConcurrentHashMap<>());
        }
        if(userTopKillMap.get(userId).getOrDefault(cityType,0) < killCount){
            userTopKillMap.get(userId).put(cityType,killCount);
            return true;
        }
        return false;
    }

    private boolean isTopToken(long userId,int tokenCount){
        if(userTopTokenMap.getOrDefault(userId,0) < tokenCount){
            userTopTokenMap.put(userId,tokenCount);
            return true;
        }
        return false;
    }

    public void addNeedInsertCityReportData(CrossFiveHeroCityReport data){
        synchronized (needInsertCityReportDataList){
            if(!needInsertCityReportDataList.contains(data)){
                needInsertCityReportDataList.add(data);
            }
        }
    }

    public void addNeedInsertCityData(CrossFiveHeroCity data){
        synchronized (needInsertCityDataList){
            if(!needInsertCityDataList.contains(data)){
                needInsertCityDataList.add(data);
            }
        }
    }

    public void addNeedUpdateCityData(CrossFiveHeroCity data){
        synchronized (needUpdateCityDataList){
            if(!needUpdateCityDataList.contains(data)){
                needUpdateCityDataList.add(data);
            }
        }
    }

    public Map<Integer,Map<Long,Integer>> getCityBattleUserIdMap() {
        return cityBattleUserIdMap;
    }

    private Object getCityPvpLock(int cityId){
        synchronized (lock){
            if(!cityPvpLockMap.containsKey(cityId)){
                cityPvpLockMap.put(cityId,new Object());
            }
            return cityPvpLockMap.get(cityId);
        }
    }
    private Object getCityTokenLock(int tokenId){
        synchronized (lock){
            if(!cityTokenLockMap.containsKey(tokenId)){
                cityTokenLockMap.put(tokenId,new Object());
            }
            return cityTokenLockMap.get(tokenId);
        }
    }
    private Object getCityBanditLock(int cityId){
        synchronized (lock){
            if(!cityBanditLockMap.containsKey(cityId)){
                cityBanditLockMap.put(cityId,new Object());
            }
            return cityBanditLockMap.get(cityId);
        }
    }

    public CrossFiveHeroMatchData getCrossFiveHeroMatchData() {
        return crossFiveHeroMatchData;
    }



    public CrossFiveHeroMatch(FiveHeroConfig tmpConfig,int inGroupId) {
        groupId = inGroupId;
        config = tmpConfig;
        initMaxRankConfig(config.getActivityId());
        if(crossFiveHeroMatchData == null){
            crossFiveHeroMatchData = new CrossFiveHeroMatchData();
            crossFiveHeroMatchData.setActivityId(config.getActivityId());
            crossFiveHeroMatchData.setGroupId(groupId);
            crossFiveHeroMatchData.setMatchId(1);
            crossFiveHeroMatchData.setInsertOption();
        }
    }

    //今日的洛阳城是不是结束了
    public boolean isTodayTokenScoreOver(){
        long nowTime = System.currentTimeMillis();
        long luoyangOverTime = config.getTodayInSideOverTime();
        if(nowTime >= luoyangOverTime){
            return true;
        }
        int matchDay = config.getMatchDay();
        Map<Integer, Map<Integer, Long>> scoreTokenMap = crossFiveHeroMatchData.getScoreTokenMap();
        for(Map<Integer, Long> dayScoreMap : scoreTokenMap.values()){
            if(dayScoreMap.getOrDefault(matchDay,0L) >= config.getLuoYangOverScore()){
                return true;
            }
        }
        return false;
    }

    public CrossFiveHeroMatch(FiveHeroConfig tmpConfig,CrossFiveHeroMatchData matchData) {
        groupId = matchData.getGroupId();
        config = tmpConfig;
        initMaxRankConfig(config.getActivityId());
        crossFiveHeroMatchData = matchData;
    }

    private void initMaxRankConfig(int activityId) {
        userMaxRankConfig = getMaxRankConfig(ActivityInfoMgr.getConditionInfoList(activityId, eGamePlayerEventType.FiveHeroUserPopularityRank.getValue()));
        unionMaxRankConfig = getMaxRankConfig(ActivityInfoMgr.getConditionInfoList(activityId, eGamePlayerEventType.FiveHeroCampUnionPopularityRank.getValue()));
        campMaxRankConfig = getMaxRankConfig(ActivityInfoMgr.getConditionInfoList(activityId, eGamePlayerEventType.FiveHeroCampScoreRank.getValue()));
    }

    private int getMaxRankConfig(List<ActivityConditionInfo> list) {
        int maxRank = 0;
        for (ActivityConditionInfo conditionInfo : list) {
            int tmp = conditionInfo.getParamList().get(1).intValue();
            if (tmp > 0 && maxRank < tmp) {
                maxRank = tmp;
            }
        }
        return maxRank;
    }

    public void addUserData(Map<Long, CrossFiveHeroUserData> map){
        userDataMap = map;
    }

    public void addUserReportData(Map<Long, List<CrossFiveHeroUserReport>> map){
        userReportMap = map;
    }

    public void addCityReportData(List<CrossFiveHeroCityReport> list){
        cityReportList = list;
    }
    public void addCityReportLuoYangData(List<CrossFiveHeroCityReport> list){
        cityReportLuoYangList = list;
    }

    public CrossFiveHeroUserData getUserData(long userId){
        return userDataMap.get(userId);
    }

    public void addUnionData(Map<String, CrossFiveHeroUnion> map){
        unionMap = map;
    }

    public ActivityInfo getActivityInfo(){
        return config.getActivityInfo();
    }

    public void timerTask() {
        //优化完了不用复活了
        checkLuoYangOpen();
        checkCityDefRevive();
        checkAttackLuoYangReset();
        checkExpAdd();
        checkTokenGetReward();
        checkTokenDayBack();
        syncLampData();
        syncCityData();
        nightOver();
        timerSaveRank();
        checkUserOnCity();
    }

    //洛阳开放了会发一条跑马灯
    public void checkLuoYangOpen(){
        //三次提醒
        long nowTime = System.currentTimeMillis();
        long todayLuoYangOpenTime = config.getTodayInSideBeginTime();
        long todayLuoYangOpenTime2 = todayLuoYangOpenTime + DateHelper.MINUTE_MILLIONS;
        long todayLuoYangOpenTime3 = todayLuoYangOpenTime2 + DateHelper.MINUTE_MILLIONS;

        //分钟内才发，不然晚上重启了也发
        if(nowTime >= todayLuoYangOpenTime && !luoYangBattleHorseTimeList.contains(todayLuoYangOpenTime) &&
            nowTime - todayLuoYangOpenTime <= DateHelper.MINUTE_MILLIONS){
            CrossFiveHeroHorseLamp lamp = new CrossFiveHeroHorseLamp();
            lamp.setType(5);
            addHorseLamp(lamp);
            luoYangBattleHorseTimeList.add(todayLuoYangOpenTime);
        }
        if(nowTime >= todayLuoYangOpenTime2 && !luoYangBattleHorseTimeList.contains(todayLuoYangOpenTime2) &&
            nowTime - todayLuoYangOpenTime2 <= DateHelper.MINUTE_MILLIONS){
            CrossFiveHeroHorseLamp lamp = new CrossFiveHeroHorseLamp();
            lamp.setType(5);
            addHorseLamp(lamp);
            luoYangBattleHorseTimeList.add(todayLuoYangOpenTime2);
        }
        if(nowTime >= todayLuoYangOpenTime3 && !luoYangBattleHorseTimeList.contains(todayLuoYangOpenTime3) &&
            nowTime - todayLuoYangOpenTime3 <= DateHelper.MINUTE_MILLIONS){
            CrossFiveHeroHorseLamp lamp = new CrossFiveHeroHorseLamp();
            lamp.setType(5);
            addHorseLamp(lamp);
            luoYangBattleHorseTimeList.add(todayLuoYangOpenTime3);
        }
    }

    public void save() {
        int crossFiveHeroMatchDataInsertCount = 0;
        int crossFiveHeroMatchDataUpdateCount = 0;
        if(crossFiveHeroMatchData.isInsertOption()){
            FiveHeroBusiness.addCrossFiveHeroMatchData(crossFiveHeroMatchData);
        }else if(crossFiveHeroMatchData.isUpdateOption()){
            FiveHeroBusiness.updateCrossFiveHeroMatchData(crossFiveHeroMatchData);
        }
        if(System.currentTimeMillis() < 1688659200000L){
            logger.info("五熊保存数据:crossFiveHeroMatchDataInsertCount:{}",crossFiveHeroMatchDataInsertCount);
            logger.info("五熊保存数据:crossFiveHeroMatchDataUpdateCount:{}",crossFiveHeroMatchDataUpdateCount);

            logger.info("五熊保存数据:needInsertCityDataList:{}",needInsertCityDataList.size());
            logger.info("五熊保存数据:needUpdateCityDataList:{}",needUpdateCityDataList.size());
            logger.info("五熊保存数据:needInsertUserReportDataList:{}",needInsertUserReportDataList.size());
            logger.info("五熊保存数据:needInsertCityReportDataList:{}",needInsertCityReportDataList.size());
        }

        List<CrossFiveHeroCity> tempInsertCityList = new ArrayList<>();
        synchronized (needInsertCityDataList){
            tempInsertCityList = new ArrayList<>(needInsertCityDataList);
            needInsertCityDataList.clear();
        }

        if (tempInsertCityList.size() > 0) {
            FiveHeroBusiness.addCrossCityDataList(tempInsertCityList);
        }

        List<CrossFiveHeroCity> tempUpdateCityList = new ArrayList<>();
        List<CrossFiveHeroCity> tempUpdateCityNoPatronsList = new ArrayList<>();
        synchronized (needUpdateCityDataList){
            for(CrossFiveHeroCity city : needUpdateCityDataList){
                if(city.isDefPatronsUpdate()){
                    city.setDefPatronsUpdate(false);
                    tempUpdateCityList.add(city);
                }else{
                    tempUpdateCityNoPatronsList.add(city);
                }
            }
            needUpdateCityDataList.clear();
        }

        if (tempUpdateCityList.size() > 0) {
            FiveHeroBusiness.updateCrossCityDataList(tempUpdateCityList);
        }
        if (tempUpdateCityNoPatronsList.size() > 0) {
            FiveHeroBusiness.updateCrossCityDataListNoPatrons(tempUpdateCityNoPatronsList);
        }



        List<CrossFiveHeroUserReport> tempInsertUserReportList = new ArrayList<>();
        synchronized (needInsertUserReportDataList){
            tempInsertUserReportList = new ArrayList<>(needInsertUserReportDataList);
            needInsertUserReportDataList.clear();
        }

        if (tempInsertUserReportList.size() > 0) {
            FiveHeroBusiness.addCrossUserReportDataList(tempInsertUserReportList);
        }

        List<CrossFiveHeroCityReport> tempInsertCityReportList = new ArrayList<>();
        synchronized (needInsertCityReportDataList){
            tempInsertCityReportList = new ArrayList<>(needInsertCityReportDataList);
            needInsertCityReportDataList.clear();
        }

        if (tempInsertCityReportList.size() > 0) {
            FiveHeroBusiness.addCrossCityReportDataList(tempInsertCityReportList);
        }
    }


    /**
     * 重新加载配置
     */
    public void reloadConfig() {

    }

    /**
     * 热更
     */
    public void repair() {

    }


    //同步变化的城池
    private void addCityChange(int cityId){
        synchronized (needSyncCityList){
            if(!needSyncCityList.contains(cityId)){
                needSyncCityList.add(cityId);
            }
        }
    }

    private void syncCityData(){
        List<Integer> tempNeedSyncCityList = new ArrayList<>();
        synchronized (needSyncCityList){
            if(needSyncCityList.size() > 0){
                tempNeedSyncCityList = new ArrayList<>(needSyncCityList);
                needSyncCityList.clear();
            }
        }
        Map<Integer, CrossFiveHeroCity> cityMap = crossFiveHeroMatchData.getCityMap();
        if(tempNeedSyncCityList.size() > 0){
            FiveHeroProto.FiveHeroCitySyncMsg.Builder syncMsg = FiveHeroProto.FiveHeroCitySyncMsg.newBuilder();
            for(Integer cityId : tempNeedSyncCityList){
                if(!cityMap.containsKey(cityId)){
                    return;
                }
                syncMsg.addCity(parseFiveHeroCityMsg(cityMap.get(cityId)));
            }
            for(long userId : new ArrayList<>(inEnterUserIdList)){
                sendPacket(ClientProtocol.U_FIVEHERO_CITY_SYNC, syncMsg, userId);
            }
        }
    }

    private void syncLampData(){
        List<CrossFiveHeroHorseLamp> tempNeedSyncLampList = new ArrayList<>();
        synchronized (needSyncLampList){
            if(needSyncLampList.size() > 0){
                tempNeedSyncLampList = new ArrayList<>(needSyncLampList);
                needSyncLampList.clear();
            }
        }
        if(tempNeedSyncLampList.size() > 0){
            FiveHeroProto.FiveHeroHorseLampSyncMsg.Builder syncMsg = FiveHeroProto.FiveHeroHorseLampSyncMsg.newBuilder();
            syncMsg.setIsSync(true);
            for(CrossFiveHeroHorseLamp lamp : tempNeedSyncLampList){
                FiveHeroProto.FiveHeroHorseLampMsg.Builder lampMsg = parseFiveHeroHorseLampMsg(lamp);
                syncMsg.addList(lampMsg);
            }
            for(long userId : new ArrayList<>(inEnterUserIdList)){
                sendPacket(ClientProtocol.U_FIVEHERO_HORSE_LAMP, syncMsg, userId);
            }
        }
    }

    //
    private FiveHeroProto.FiveHeroHorseLampMsg.Builder parseFiveHeroHorseLampMsg(CrossFiveHeroHorseLamp lp){
        FiveHeroProto.FiveHeroHorseLampMsg.Builder lampMsg = FiveHeroProto.FiveHeroHorseLampMsg.newBuilder();
        lampMsg.setType(lp.getType());
        CrossFiveHeroUserData userData = getUserData(lp.getAttUserId());
        UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(lp.getAttUserId());
        lampMsg.setAttCampId(0);
        lampMsg.setAttNickName("");
        lampMsg.setAttServerId(0);
        lampMsg.setAttVipExp(0);
        lampMsg.setDecoration("");
        lampMsg.setTime(0);
        if(userBaseInfo != null && userData != null){
            lampMsg.setAttCampId(userData.getCampId());
            lampMsg.setAttNickName(userBaseInfo.getNickName());
            lampMsg.setAttServerId(userBaseInfo.getServerId());
            lampMsg.setAttVipExp(userBaseInfo.getVipExp());
            lampMsg.setDecoration(userBaseInfo.getDecoration());
            //要判断vip的显示和隐藏
            lampMsg.setTime(userBaseInfo.getHideVipAndAddress());
        }else{
            //没有攻击玩家的阵营积分达到多少了的跑马灯的积分在这里
            if(lp.getAttUserId() != 0){
                lampMsg.setAttCampId((int)lp.getAttUserId());
            }
        }
        CrossFiveHeroUserData defUserData = getUserData(lp.getDefUserId());
        UserBaseInfo defUserBaseInfo = CrossUserMgr.getUserBaseInfo(lp.getDefUserId());
        lampMsg.setDefCampId(0);
        lampMsg.setDefNickName("");
        lampMsg.setDefServerId(0);
        if(defUserBaseInfo != null && defUserData != null){
            lampMsg.setDefCampId(defUserData.getCampId());
            lampMsg.setDefNickName(defUserBaseInfo.getNickName());
            lampMsg.setDefServerId(defUserBaseInfo.getServerId());
        }
        lampMsg.setKillNum(lp.getKillNum());
        lampMsg.setTokenNum(lp.getTokenNum());
        lampMsg.setCityId(lp.getCityId());
        return lampMsg;
    }

    private void addHorseLamp(CrossFiveHeroHorseLamp lp){
        synchronized (lampList){
            lampList.sort(new HorseTimeSort());
            if(lampList.size() >= config.getLampNum()){
                lampList.remove(lampList.size() - 1);
            }
            lampList.add(lp);
            needSyncLampList.add(lp);
        }
    }

    //领取奖励发送奖励
    private int sendRankReward(long userId, int conditionType) {
        CrossFiveHeroUserData userData = getUserData(userId);

        // 资格
        if (!isAble(userData)) {
            return GameErrorCode.E_FIVE_HERO_NO_ABLE;
        }

        // 拿职位参数
        CrossFiveHeroUnion join = unionMap.get(userData.getUnionUid());
        CrossFiveHeroUnionMember member = join.getMemberMap().get(userId);
        int position = member.getPosition();

        // 拿阵营排名参数
        LinkedList<CrossFiveHeroRank> campRankList = getCampScoreRankList(true);
        String myCampId = String.valueOf(userData.getCampId());
        int myCampRank = -1;
        int campRankNum = 0;
        for (CrossFiveHeroRank rank : campRankList) {
            campRankNum++;
            if (Objects.equals(rank.getId(), myCampId)) {
                myCampRank = campRankNum;
                break;
            }
        }

        // 拿榜单
        String myId;
        LinkedList<CrossFiveHeroRank> rankList;
        if (conditionType == eGamePlayerEventType.FiveHeroUserPopularityRank.getValue()) {
            rankList = userRank.getRankList();
            myId = String.valueOf(userId);
        } else if (conditionType == eGamePlayerEventType.FiveHeroCampUnionPopularityRank.getValue()) {
            CrossFiveHeroRankListModel unionRank = campUnionRankMap.get(userData.getCampId());
            rankList = unionRank == null ? new LinkedList<>() : unionRank.getRankList();
            myId = userData.getUnionUid();
        } else if (conditionType == eGamePlayerEventType.FiveHeroCampScoreRank.getValue()) {
            rankList = campRankList;
            myId = String.valueOf(userData.getCampId());
        } else {
            return GameErrorCode.E_FIVE_HERO_PARAMS_ERR;
        }

        // 【拿榜单排名】
        int myRank = -1;
        int num = 0;
        for (CrossFiveHeroRank rank : rankList) {
            num++;
            if (Objects.equals(rank.getId(), myId)) {
                myRank = num;
                break;
            }
        }

        FiveHeroProto.CrossFiveHeroGetRankRewardRespMsg.Builder builder = FiveHeroProto.CrossFiveHeroGetRankRewardRespMsg.newBuilder();
        builder.setRet(0);
        builder.setActivityId(config.getActivityInfo().getActivityId());
        builder.setConditionType(conditionType);
        builder.setPosition(position);
        builder.setRank(myRank);
        builder.setCampRank(myCampRank);
        builder.setUnionId(userData.getUnionUid());
        sendPacket(GameProtocol.S_FIVEHERO_GET_RANK_REWARD_FROM_CROSS, builder, userId);
        return 0;
    }


    public void getRankReward(long userId, FiveHeroProto.FiveHeroGetRankRewardReqMsg reqMsg) {
        int ret = sendRankReward(userId, reqMsg.getConditionType());
        if (ret != 0) {
            FiveHeroProto.FiveHeroGetRankRewardRespMsg.Builder builder = FiveHeroProto.FiveHeroGetRankRewardRespMsg.newBuilder();
            builder.setRet(ret);
            sendPacket(ClientProtocol.U_FIVEHERO_GET_RANK_REWARD, builder, userId);
        }
    }

    //红读了
    public void readRedDot(long userId, FiveHeroProto.FiveHeroReadRedDotReqMsg reqMsg) {
        CrossFiveHeroUserData userData = getUserData(userId);
        if (isAble(userData)) {
            userData.getRedDotMap().remove(reqMsg.getType());
            fhAc.addNeedUpdateUserData(userData);
        }
    }

    private void addRedDot(long userId, eFiveHeroRedDotType type) {
        CrossFiveHeroUserData userData = getUserData(userId);
        if (userData.getRedDotMap().containsKey(type.getValue())) {
            return;
        }
        userData.getRedDotMap().put(type.getValue(), System.currentTimeMillis());
        fhAc.addNeedUpdateUserData(userData);

        FiveHeroProto.FiveHeroRedDotSyncMsg.Builder builder = FiveHeroProto.FiveHeroRedDotSyncMsg.newBuilder();
        builder.setActivityId(config.getActivityId());
        builder.addType(type.getValue());
        sendPacket(ClientProtocol.U_FIVEHERO_RED_DOT_SYNC, builder, userData.getUserId());
    }

    //获取道具加成
    public void getAbilityAdd(long userId, FiveHeroProto.FiveHeroAbilityAddReqMsg reqMsg) {
        long searchUserId = reqMsg.getUserId();
        FiveHeroProto.FiveHeroAbilityAddRespMsg.Builder respMsg = FiveHeroProto.FiveHeroAbilityAddRespMsg.newBuilder();
        CrossFiveHeroUserData userData = getUserData(searchUserId);
        respMsg.setPatronsCount(userData.getPatronsMap().size());
        respMsg.setPatronsAdd(getAcAllAddValue(searchUserId));
        respMsg.setItemValueAdd(getItemAdd(searchUserId));
        respMsg.setItemPerAdd((int)getItemPerAdd(searchUserId));
        respMsg.setTechPerAdd((int)getCampLevelPerAdd(searchUserId));
        respMsg.setItemPerAddValue(getItemPerAddValue(searchUserId));
        respMsg.setTechPerAddValue(getCampLevelPerAddValue(searchUserId));
        Map<Integer, Integer> itemMap = new ConcurrentHashMap<>(userData.getAddItemMap());
        for(GoodsInfo goodsInfo : GoodsMgr.getFiveHeroAddItem()){
            if(!itemMap.containsKey(goodsInfo.getGoodsId())){
                itemMap.put(goodsInfo.getGoodsId(),0);
            }
        }
        for(int goodId : itemMap.keySet()){
            FiveHeroProto.FiveHeroAbilityAddItemMsg.Builder itemMsg = FiveHeroProto.FiveHeroAbilityAddItemMsg.newBuilder();
            itemMsg.setItemId(goodId);
            itemMsg.setNum(itemMap.get(goodId));
            respMsg.addItems(itemMsg);
        }
        respMsg.setCurioAddition(userData.getCurioAddition());
        respMsg.setUpdateTime((int)(userData.getUpdatePatronsTime()/1000));
        sendPacket(ClientProtocol.U_FIVEHERO_ABILITY_ADD, respMsg, userId);
    }

    public void abilityAddItem(long userId, FiveHeroProto.CrossFiveHeroAddItemMsg reqMsg) {
        int goodIds = reqMsg.getItem();
        int num = reqMsg.getNum();
        CrossFiveHeroUserData userData = getUserData(userId);
        Map<Integer, Integer> addItemMap = userData.getAddItemMap();
        addItemMap.put(goodIds,addItemMap.getOrDefault(goodIds,0) + num);
        userData.setAddItemMap(addItemMap);
        fhAc.addNeedUpdateUserData(userData);
        GoodsInfo goodsInfo = GoodsMgr.getGoodsInfo(goodIds);
        List<BigInteger> pList = goodsInfo.getParamList();
        long addValue = 0;
        long addPerValue = 0;
        //固定值加成
        if(pList.get(0).compareTo(BigInteger.ZERO) != 0){
            addValue = pList.get(0).longValue() * num;
        }
        //百分比加成
        if(pList.get(1).compareTo(BigInteger.ZERO) != 0){
            addPerValue = pList.get(1).longValue() * num;
        }
        if(addValue != 0 || addPerValue != 0){
            for(CrossFiveHeroPatrons p : userData.getPatronsMap().values()){
                BigDecimal ab = BigDecimal.valueOf(p.getAbility());
                ab = ab.multiply(BigDecimal.valueOf(addPerValue)).divide(BigDecimal.valueOf(1000),0,BigDecimal.ROUND_UP);
                long addPatronValue =  ab.longValue() + addValue;
                long newValue = getPatronsMaxBlood(p);
                /*CrossFiveHeroLog.addLogFiveHeroPatronsUpdate(new LogFiveHeroPatronsUpdate(
                        groupId,
                        config.getActivityInfo().getActivityId(),
                        userId,
                        userData.getCampId(),
                        p.getId(),
                        1,
                        addPatronValue,
                        newValue - addPatronValue,
                        newValue
                ));*/
            }
        }
        syncUserDataMsg(userId);
    }

    //查看每日分数
    public void lookScore(long userId, FiveHeroProto.FiveHeroCampScoreDetailReqMsg reqMsg) {
        FiveHeroProto.FiveHeroCampScoreDetailRespMsg.Builder respMsg = FiveHeroProto.FiveHeroCampScoreDetailRespMsg.newBuilder();
        int campId = reqMsg.getCampId();
        Map<Integer, Map<Integer, Long>> aMap = crossFiveHeroMatchData.getScoreCityMap();
        Map<Integer, Map<Integer, Long>> bMap = crossFiveHeroMatchData.getScoreTokenMap();
        Map<Integer, Map<Integer, Long>> pMap = crossFiveHeroMatchData.getPopMap();
        Map<Integer, Long> aaMap = aMap.getOrDefault(campId,new ConcurrentHashMap<>());
        Map<Integer, Long> bbMap = bMap.getOrDefault(campId,new ConcurrentHashMap<>());
        Map<Integer, Long> ppMap = pMap.getOrDefault(campId,new ConcurrentHashMap<>());
        LinkedList<CrossFiveHeroRank> cityScoreList = getCampScoreRankList(false);
        Map<Integer,Long> cityScoreMap = new ConcurrentHashMap<>();
        for(CrossFiveHeroRank rank : cityScoreList){
            cityScoreMap.put(Integer.valueOf(rank.getId()),rank.getValue());
        }
        int todayMatchDay = config.getMatchDay();
        for(int i = 1; i<= todayMatchDay; i++){
            FiveHeroProto.FiveHeroCampScoreDetailTempMsg.Builder dayMsg = FiveHeroProto.FiveHeroCampScoreDetailTempMsg.newBuilder();
            dayMsg.setDay(i);
            dayMsg.setScore(aaMap.getOrDefault(i,0L) + bbMap.getOrDefault(i,0L) + cityScoreMap.getOrDefault(campId,0L));
            dayMsg.setPopularity(ppMap.getOrDefault(i,0L));
            respMsg.addDetail(dayMsg);
        }
        long allCityScore = 0;
        long allTokenScore = 0;
        for(int i = 1; i <= todayMatchDay; i++){
            allTokenScore = allTokenScore + bbMap.getOrDefault(i,0L);
            allCityScore = allCityScore + aaMap.getOrDefault(i,0L);
        }
        respMsg.setTokenScore(allTokenScore);
        respMsg.setCityScore(allCityScore + cityScoreMap.getOrDefault(campId,0L));
        sendPacket(ClientProtocol.U_FIVEHERO_SCORE_DETAIL, respMsg, userId);
    }

    public void addToddayPop(long userId, long cutValue) {
        Map<Integer, Map<Integer, Long>> popMap = crossFiveHeroMatchData.getPopMap();
        CrossFiveHeroUserData userData = getUserData(userId);
        if(userData.getCampId() == 0){
            return;
        }
        int day = config.getMatchDay();
        synchronized (popMap){
            if(!popMap.containsKey(userData.getCampId())){
                popMap.put(userData.getCampId(),new ConcurrentHashMap<>());
            }
            Map<Integer, Long> dayMap = popMap.get(userData.getCampId());
            dayMap.put(day,dayMap.getOrDefault(day,0L) + cutValue);
            crossFiveHeroMatchData.setPopMap(popMap);
        }
    }

    public void battlePvpRecord(long userId, FiveHeroProto.FiveHeroBattleRecordReqMsg reqMsg) {
        CrossFiveHeroUserData userData = getUserData(userId);
        int cityId = reqMsg.getCityId();
        Map<Integer, CrossFiveHeroCity> cityMap = crossFiveHeroMatchData.getCityMap();
        CrossFiveHeroCity city = cityMap.get(cityId);
        FiveHeroProto.FiveHeroBattleRecordRespMsg.Builder respMsg = FiveHeroProto.FiveHeroBattleRecordRespMsg.newBuilder();
        respMsg.setRet(0);
        if(city != null){
            Map<Long, Integer> killMap = new ConcurrentHashMap<>(city.getKillCountMap());
            //todo-xx 这个是血量
            killMap.remove(1L);
            if(killMap.size() > 0){
                LinkedList<CrossFiveHeroRank> rankList = new LinkedList<>();
                for(long killUserId : killMap.keySet()){
                    rankList.add(new CrossFiveHeroRank(killUserId + "" ,killMap.get(killUserId),0));
                }
                rankList.sort(new CrossFiveHeroRankSort());
                int rankNum = 0;
                for(CrossFiveHeroRank rank : rankList){
                    rankNum++;
                    long killUserId = Long.valueOf(rank.getId());
                    UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(killUserId);
                    if(userBaseInfo != null){
                        FiveHeroProto.FiveHeroBattleRecordTempMsg.Builder rankMsg = FiveHeroProto.FiveHeroBattleRecordTempMsg.newBuilder();
                        rankMsg.setRank(rankNum);
                        rankMsg.setNickName(userBaseInfo.getNickName());
                        rankMsg.setKillCount((int)rank.getValue());
                        respMsg.addRecords(rankMsg);
                    }
                }
            }
        }
        sendPacket(ClientProtocol.U_FIVEHERO_PVP_DAMAGE, respMsg, userId);
    }

    public void tokenScore(long userId, FiveHeroProto.FiveHeroTokenScoreReqMsg reqMsg) {
        CrossFiveHeroUserData userData = getUserData(userId);
        if(userData != null && !userData.isOverFlag()){
            syncTokenScore(userId,false);
            if(isTodayTokenScoreOver()){
//                userData.setOverFlag(true);
            }
        }else{
            FiveHeroProto.FiveHeroTokenScoreSyncMsg.Builder respMsg = FiveHeroProto.FiveHeroTokenScoreSyncMsg.newBuilder();
            respMsg.setOver(true);
            sendPacket(ClientProtocol.U_FIVEHERO_TOKEN_SCORE, respMsg, userId);
        }
    }

    public void syncTokenScore(long userId,boolean isSync) {
        FiveHeroProto.FiveHeroTokenScoreSyncMsg.Builder respMsg = FiveHeroProto.FiveHeroTokenScoreSyncMsg.newBuilder();
        boolean isOver = isTodayTokenScoreOver();
        respMsg.setOver(isOver);
        for(int i = 1; i <= config.getCampCount(); i++){
            FiveHeroProto.FiveHeroTokenScoreTempMsg.Builder campMsg = FiveHeroProto.FiveHeroTokenScoreTempMsg.newBuilder();
            campMsg.setCampId(i);
            campMsg.setValue((int)getCampTodayTokenScore(i));
            campMsg.setAllValue((int)getCampScore(i));
            campMsg.setSpeed(getCampScoreSpeed(i));
            respMsg.addTokenScores(campMsg);
        }
        if(!isSync && isOver){
            int matchDay = config.getMatchDay();
            long topUserId = 0;
            long topScore = 0;
            int userCampId = 0;
            for(CrossFiveHeroUserData userData : userDataMap.values()){
                long value = userData.getTokeScoreMap().getOrDefault(matchDay,0L);
                if(value > topScore){
                    topScore = value;
                    topUserId = userData.getUserId();
                    userCampId = userData.getCampId();
                }
            }
            if(topUserId != 0){
                UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(topUserId);
                if(userBaseInfo != null){
                    respMsg.setTopUser(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
                    respMsg.setScore((int)topScore);
                    respMsg.setTopUserCampId(userCampId);
                }
            }
        }
        sendPacket(ClientProtocol.U_FIVEHERO_TOKEN_SCORE, respMsg, userId);
    }

    public Map<Integer, CrossFiveHeroRankListModel> getCampUnionRankMap() {
        return campUnionRankMap;
    }

    static class HorseTimeSort implements Comparator<CrossFiveHeroHorseLamp> {
        @Override
        public int compare(CrossFiveHeroHorseLamp o1, CrossFiveHeroHorseLamp o2) {
            if (o1.getTime() == o2.getTime()) {
                return 0;
            }
            if (o1.getTime() > o2.getTime()) {
                return -1;
            }
            return 1;
        }
    }

    //取出所有玩家的前六(配置)门客
    private List<CrossFiveHeroPatrons> getTopNumPatronsList(int pNum){
        List<CrossFiveHeroPatrons> patronsList = new ArrayList<>();
        for(CrossFiveHeroUserData userData : userDataMap.values()){
            patronsList.addAll(getTopNumUserPatronsList(userData,pNum));
        }
        return patronsList;
    }

    //山贼的
    private List<CrossFiveHeroPatrons> getAllTopNumOccPatronsList(int pNum){
        List<CrossFiveHeroPatrons> patronsList = new ArrayList<>();
        for(CrossFiveHeroUserData userData : userDataMap.values()){
            patronsList.addAll(getTopNumOccUserPatronsList(userData,pNum));
        }
        return patronsList;
    }

    //对应所有职业前六门客取出来
    private List<CrossFiveHeroPatrons> getTopNumOccUserPatronsList(CrossFiveHeroUserData userData,int num){
        int topNum = num;
        List<CrossFiveHeroPatrons> top6List = new ArrayList<>();
        Map<Integer,List<CrossFiveHeroPatrons>> occMap = new ConcurrentHashMap<>();
        for(CrossFiveHeroPatrons patrons : userData.getPatronsMap().values()){
            PatronsInfo patronsInfo = PatronsMgr.getPatronsInfo(patrons.getId());
            if(!occMap.containsKey(patronsInfo.getOccupation())){
                occMap.put(patronsInfo.getOccupation(),new ArrayList<>());
            }
            occMap.get(patronsInfo.getOccupation()).add(patrons);
        }
        for(int occId : occMap.keySet()){
            List<CrossFiveHeroPatrons> pList = occMap.get(occId);
            pList.sort(new PatronsQualificationSort());
            int i = 0;
            for(CrossFiveHeroPatrons addP : pList){
                if(i < topNum){
//                    logger.debug("玩家{}的职业{}的第{}名门客{}能力{}",userData.getUserId(),occId,i + 1,addP.getId(),addP.getAbility());
                    top6List.add(addP);
                    i++;
                }else{
                    break;
                }
            }
        }
        return top6List;
    }

    //对应职业前六门客取出来
    private List<CrossFiveHeroPatrons> getTopNumOccUserPatronsList(CrossFiveHeroUserData userData,int num,int occId){
        int topNum = num;
        List<CrossFiveHeroPatrons> top6List = new ArrayList<>();
        Map<Integer,List<CrossFiveHeroPatrons>> occMap = new ConcurrentHashMap<>();
        for(CrossFiveHeroPatrons patrons : userData.getPatronsMap().values()){
            PatronsInfo patronsInfo = PatronsMgr.getPatronsInfo(patrons.getId());
            if(!occMap.containsKey(patronsInfo.getOccupation())){
                occMap.put(patronsInfo.getOccupation(),new ArrayList<>());
            }
            occMap.get(patronsInfo.getOccupation()).add(patrons);
        }
        List<CrossFiveHeroPatrons> pList = occMap.get(occId);
        if(pList == null || pList.size() == 0){
            return top6List;
        }
        pList.sort(new PatronsQualificationSort());
        int i = 0;
        for(CrossFiveHeroPatrons addP : pList){
            if(i < topNum){
//                    logger.debug("玩家{}的职业{}的第{}名门客{}能力{}",userData.getUserId(),occId,i + 1,addP.getId(),addP.getAbility());
                top6List.add(addP);
                i++;
            }else{
                break;
            }
        }
        return top6List;
    }
    //所有职业都在的前六
    private List<CrossFiveHeroPatrons> getTopNumUserPatronsList(CrossFiveHeroUserData userData,int num){
        int topNum = num;
        List<CrossFiveHeroPatrons> top6List = new ArrayList<>();
        List<CrossFiveHeroPatrons> allList = new ArrayList<>();
        allList = new ArrayList<>(userData.getPatronsMap().values());
        allList.sort(new PatronsQualificationSort());
        int i = 0;
        for(CrossFiveHeroPatrons addP : allList){
            if(i < topNum){
//                    logger.debug("玩家{}的职业{}的第{}名门客{}能力{}",userData.getUserId(),occId,i + 1,addP.getId(),addP.getAbility());
                top6List.add(addP);
                i++;
            }else{
                break;
            }
        }
        return top6List;
    }

    //对应职业的前几门客
    private List<CrossFiveHeroPatrons> getTopNumOccPatronsList(int tNum, int occId){
        List<CrossFiveHeroPatrons> patronsList = new ArrayList<>();
        for(CrossFiveHeroUserData userData : userDataMap.values()){
            if(occId == 0){
                patronsList.addAll(getTopNumOccUserPatronsList(userData,tNum));
            }else{
                patronsList.addAll(getTopNumOccUserPatronsList(userData,tNum,occId));
            }
        }
        return patronsList;
    }

    //获取除了战胜玩家的剩余的人的前6门客
    private List<CrossFiveHeroPatrons> getAllCampPatronsList(long bangUserId,int occId){
        CrossFiveHeroUserData bangUserData = getUserData(bangUserId);
        List<CrossFiveHeroPatrons> patronsList = new ArrayList<>();
        for(CrossFiveHeroUserData userData : userDataMap.values()){
            if(bangUserData != null && userData.getCampId() != bangUserData.getCampId()){
                continue;
            }
            if(userData.getUserId() == bangUserId && config.getMakePvpKillPatronsNum() != 0){
                continue;
            }
            if(occId == 0){
                patronsList.addAll(getTopNumOccUserPatronsList(userData,config.getMakePvpTopPatronsNum()));
            }else{
                patronsList.addAll(getTopNumOccUserPatronsList(userData,config.getMakePvpTopPatronsNum(),occId));
            }
        }
        return patronsList;
    }

    //从分组中随机一个门客 这里™又要改
    private CrossFiveHeroPatrons getOnePatrons(List<Integer> weightList,Map<Integer,List<CrossFiveHeroPatrons>> groupPatronsMap){
        //有门客可以随机的权重
        List<Integer> hasPatronsWeightList = new ArrayList<>();
        List<CrossFiveHeroPatrons> randomList = new ArrayList<>();
        //组已经变了，有的不进去了
        List<List<CrossFiveHeroPatrons>> hasPatronsGroupList = new ArrayList<>();
        int totalWeight = 0;
        for(int i = 0; i < weightList.size() ; i++){
            if(groupPatronsMap.get(i).size() > 0 && weightList.get(i) > 0){
                totalWeight += weightList.get(i);
                hasPatronsWeightList.add(weightList.get(i));
                hasPatronsGroupList.add(groupPatronsMap.get(i));
            }
        }
        if(totalWeight <= 0){
            return null;
        }
        int randomNum = randomHelper.next(0, totalWeight);
        for (int i = 0; i < hasPatronsWeightList.size(); i++) {
            int value = hasPatronsWeightList.get(i);
            if (randomNum < value) {
                randomList = hasPatronsGroupList.get(i);
                break;
            }
            randomNum -= value;
        }
        //没有门客可以随机了
        if(randomList.size() == 0){
            logger.debug("有bug，赶紧改");
            return null;
        }
        int randomPatronsIndex = randomHelper.next(0, randomList.size());
        CrossFiveHeroPatrons p = randomList.get(randomPatronsIndex);
        randomList.remove(randomPatronsIndex);
        return p;
    }

    //返回分组后的分组门客 改版了，不是均分了，历史保留代码
    private Map<Integer,List<CrossFiveHeroPatrons>> makePatronsMap(List<Integer> weightList,List<CrossFiveHeroPatrons> allPatronsList){
        int groupSize = weightList.size();
        int groupPatronsCount = allPatronsList.size()/groupSize;
        Map<Integer,List<CrossFiveHeroPatrons>> groupPatronsMap = new ConcurrentHashMap<>();
        for(int i = 0;i < groupSize; i++){
            groupPatronsMap.put(i,new ArrayList<>());
        }
        //0开始的,除不尽他妈就不管了，需求也没写，最后几个就不要了
        for (int groupId : groupPatronsMap.keySet()){
           List<CrossFiveHeroPatrons> pList = groupPatronsMap.get(groupId);
           //最后一组全部加上去吧
           if(groupId == groupSize - 1){
               pList.addAll(allPatronsList);
               continue;
           }
           while (pList.size() < groupPatronsCount){
               if(allPatronsList.size() <= 0){
                   break;
               }
               pList.add(allPatronsList.get(0));
               allPatronsList.remove(0);
           }
        }
        return groupPatronsMap;
    }


    //获取每个分组会被分多少个人
    private List<Integer> getPerPatronsCountList(List<Integer> pCountList, int pCount){
        List<Integer> countList = new ArrayList<>();
        BigDecimal value = BigDecimal.valueOf(pCount);
        for(int gCountPer : pCountList){
            //向上取整
            BigDecimal gaga = value.multiply(BigDecimal.valueOf(gCountPer)).divide(BigDecimal.valueOf(1000),0,BigDecimal.ROUND_DOWN);
            int gCountP = gaga.intValue();
            //总的加起来有多少了，要扣掉，就是该有人，比如100人，配了200千分比和400千分比，就是20人，20人
            int nowCount = 0;
            for(int gcp : countList){
                nowCount = nowCount + gcp;
            }
            //这个组有多少人
            int addValue = gCountP - nowCount;
            if(addValue <= 0){
                addValue = 1;
            }
            countList.add(addValue);
        }
        //校验一下
        int allCount = 0;
        for(int gcp : countList){
            allCount = allCount + gcp;
        }
        if(allCount != pCount){
            logger.debug("策划改了每一个租必须有一个门客，不相等了。所有门客{}个，分出来{}个",pCount,allCount);
        }
        return countList;
    }

    //获取权重占比应该获得的门客数量
    private List<Integer> getWeightPatronsCountList(List<Integer> wightList, int pCount){
        List<Integer> countList = new ArrayList<>();
        BigDecimal value = BigDecimal.valueOf(pCount);
        //不是权重了，是改了，改来改去的
        int allWeight = 1000;
        for(int wight : wightList){
            //向上取整
            BigDecimal gaga = value.multiply(BigDecimal.valueOf(wight)).divide(BigDecimal.valueOf(allWeight),0,BigDecimal.ROUND_DOWN);
            int gCountP = gaga.intValue();
            int nowCount = 0;
            for(int gcp : countList){
                nowCount = nowCount + gcp;
            }
            //这个组有多少人
            int addValue = gCountP - nowCount;
            countList.add(addValue);
        }
        //校验一下
        int allCount = 0;
        for(int gcp : countList){
            allCount = allCount + gcp;
        }
        if(allCount != pCount){
            logger.debug("抽取门客的时候，抽取的总数和总的门客数不一样,总的{},分配的{}",allCount,pCount);
        }
        return countList;
    }
    /**
     *
     * @param pCountList 用来百分比玩家门客的
     * @param weightList
     * @param allPatronsList
     * @return
     */
    private Map<Integer,List<CrossFiveHeroPatrons>> makePatronsMapV5(List<Integer> pCountList,List<Integer> weightList,List<CrossFiveHeroPatrons> allPatronsList){
        if(allPatronsList.size() == 0){
            logger.debug("没有拿到门客");
        }
        allPatronsList.sort(new PatronsQualificationSort());
        int groupSize = weightList.size();
        List<Integer> countList = getPerPatronsCountList(pCountList,allPatronsList.size());
        Map<Integer,List<CrossFiveHeroPatrons>> groupPatronsMap = new ConcurrentHashMap<>();
        for(int i = 0;i < groupSize; i++){
            groupPatronsMap.put(i,new ArrayList<>());
        }
        //0开始的,除不尽他妈就不管了，需求也没写，最后几个就不要了
        for (int groupId : groupPatronsMap.keySet()){
           int groupPatronsCount = countList.get(groupId);
           List<CrossFiveHeroPatrons> pList = groupPatronsMap.get(groupId);
           //最后一组全部加上去吧
           if(groupId == groupSize - 1){
               pList.addAll(allPatronsList);
               continue;
           }
           while (pList.size() < groupPatronsCount){
               if(allPatronsList.size() <= 0){
                   break;
               }
               pList.add(allPatronsList.get(0));
               allPatronsList.remove(0);
           }
        }
        //校验一下
        for(int groupId : groupPatronsMap.keySet()){
            List<CrossFiveHeroPatrons> pList = groupPatronsMap.get(groupId);
            if(pList.size() == 0){
                logger.debug("给门客分组的时候，有分不到的,第{}组,门客总数{}",groupId,countList.get(groupId));
                //不会出现这种情况内网就直接第一组放人吧
                pList.addAll(groupPatronsMap.get(0));
            }
        }
        return groupPatronsMap;
    }

    private Map<Integer,List<CrossFiveHeroPatrons>> copySelectMap(Map<Integer,List<CrossFiveHeroPatrons>> patronsMap){
        Map<Integer,List<CrossFiveHeroPatrons>> rMap = new ConcurrentHashMap<>();
        for(int groupId : patronsMap.keySet()){
            rMap.put(groupId,new ArrayList<>(patronsMap.get(groupId)));
        }
        return rMap;
    }

    //生成守军
    private List<CrossFiveHeroPatrons> makeBattleDefTeam(Map<Integer,List<CrossFiveHeroPatrons>> patronsMap,List<Integer> weightList,int patronCount){
        List<CrossFiveHeroPatrons> list = new ArrayList<>();
        if(patronCount <= 0){
            return list;
        }
        List<Integer> gPCountList = getWeightPatronsCountList(weightList,patronCount);
        logger.debug("每一组要抽取的人数");
        for(int i = 0;i < gPCountList.size(); i++){
            int groupCount = gPCountList.get(i);
            logger.debug("第{}组，需要门客{}个",i+1,groupCount);
        }
        for(int i = 0;i < patronsMap.size(); i++){
            List<CrossFiveHeroPatrons> pList = patronsMap.get(i);
            logger.debug("第{}组，有门客{}个",i+1,pList.size());
        }
        for(int i = 0; i < gPCountList.size();i++){
            int pCount = gPCountList.get(i);
            List<CrossFiveHeroPatrons> oList = patronsMap.get(i);
            List<CrossFiveHeroPatrons> rList = new ArrayList<>(oList);
            for(int j=0;j < pCount;j++){
                int index = randomHelper.next(0,rList.size());
                list.add(rList.get(index));
                rList.remove(index);
                if(rList.size() == 0){
                    logger.debug("抽取门客做做守军不够了要重新抽，在第{}组中",i+1);
                    rList = new ArrayList<>(oList);
                }
            }
        }
        if(patronCount != list.size()){
            logger.debug("抽取门客做做守军异常,数量不等于配置");
        }
        return list;
    }

    private Map<Integer,CrossFiveHeroBattlePatrons> getRandomPatronsPveV2(FiveHeroCityConfig cityConfig){
        int occId = cityConfig.getJobBuffEffectList().get(0);
        Map<Integer,CrossFiveHeroBattlePatrons> battlePatronsMap = new ConcurrentHashMap<>();
        Map<Integer, FiveHeroTypeConfig> typeMap = config.getTypeConfigMap();
        FiveHeroTypeConfig typeConfig = typeMap.get(cityConfig.getType());
        //随机出来的门客
        int num = typeConfig.getTeamNum();
        List<CrossFiveHeroPatrons> allPatronsList = getTopNumOccPatronsList(config.getMakePvpTopPatronsNum(),occId);
        logger.debug("城池等级{},城池id{},生成地图时总的门客数{}",cityConfig.getType(),cityConfig.getId(),allPatronsList.size());
        Map<Integer,List<CrossFiveHeroPatrons>> patronsMap = makePatronsMapV5(typeConfig.getPveUserPerList(),typeConfig.getPvePatronsWeightList(),allPatronsList);
        List<CrossFiveHeroPatrons> selectPatronList = makeBattleDefTeam(patronsMap,typeConfig.getPvePatronsWeightList(),num);
        for(int i = 0; i < selectPatronList.size(); i++){
            CrossFiveHeroPatrons p = selectPatronList.get(i);
            CrossFiveHeroBattlePatrons battlePatrons = makeBattlePatrons(p,i+1);
            battlePatronsMap.put(i+1,battlePatrons);
        }

        return battlePatronsMap;
    }

    private Map<Integer,CrossFiveHeroBattlePatrons> getRandomPatronsPvpV2(FiveHeroCityConfig cityConfig,CrossFiveHeroUserData bangUserData){
        int occId = cityConfig.getJobBuffEffectList().get(0);
        Map<Integer,CrossFiveHeroBattlePatrons> battlePatronsMap = new ConcurrentHashMap<>();
        Map<Integer, FiveHeroTypeConfig> typeMap = config.getTypeConfigMap();
        FiveHeroTypeConfig typeConfig = typeMap.get(cityConfig.getType());
        //随机出来的门客
        int num = typeConfig.getTeamNum();
        if(num > 0){
            List<CrossFiveHeroPatrons> bangUserPatronsList = new ArrayList<>();
            if(bangUserData != null){
                if(occId != 0){
                    bangUserPatronsList = getTopNumOccUserPatronsList(bangUserData,config.getMakePvpKillPatronsNum(),occId);
                }else{
                    bangUserPatronsList = getTopNumOccUserPatronsList(bangUserData,config.getMakePvpKillPatronsNum());
                }
//                logger.debug("玩家{}占领了{}城市，拉到{}个门客参战",bangUserData.getUserId(),cityConfig.getId(),bangUserPatronsList.size());
            }
            int gagaNum = 0;
            for(CrossFiveHeroPatrons pa : bangUserPatronsList){
                CrossFiveHeroBattlePatrons battlePatrons = makeBattlePatrons(pa,gagaNum+1);
                battlePatronsMap.put(gagaNum+1,battlePatrons);
                gagaNum++;
                //不可能
                if(gagaNum >= num){
                    break;
                }
            }
            List<CrossFiveHeroPatrons> allPatronsList = getAllCampPatronsList(bangUserData == null?0:bangUserData.getUserId(),occId);
            logger.debug("城池等级{},城池id{},总的门客数{}",cityConfig.getType(),cityConfig.getId(),allPatronsList.size());
            Map<Integer,List<CrossFiveHeroPatrons>> patronsMap = makePatronsMapV5(typeConfig.getPveUserPerList(),typeConfig.getPvePatronsWeightList(),allPatronsList);
            logger.debug("开始抽取非尾刀人的守军，配置类型{}",typeConfig.getType());
            List<CrossFiveHeroPatrons> selectPatronList = makeBattleDefTeam(patronsMap,typeConfig.getPvePatronsWeightList(),num - gagaNum);
            for(int i = 0; i < selectPatronList.size(); i++){
                CrossFiveHeroPatrons p = selectPatronList.get(i);
                CrossFiveHeroBattlePatrons battlePatrons = makeBattlePatrons(p,i+1 + gagaNum);
                battlePatronsMap.put(i+1 + gagaNum,battlePatrons);
            }
            logger.debug("玩家{}占领了{}城市，拉到{}个其他门客参战",bangUserData == null?0:bangUserData.getUserId(),cityConfig.getId(),selectPatronList.size());
        }
        return battlePatronsMap;
    }

    //洛阳城随机战令给对应的门客拿着 战令id 门客
    private Map<Integer,CrossFiveHeroToken> getRandomTokenLuoYang(FiveHeroCityConfig cityConfig){
        Map<Integer, FiveHeroOrderConfig> orderMap = config.getOrderConfigMap();
        Map<Integer,CrossFiveHeroToken> tokenMap = new ConcurrentHashMap<>();
        Map<Integer, FiveHeroTypeConfig> typeMap = config.getTypeConfigMap();
        FiveHeroTypeConfig typeConfig = typeMap.get(cityConfig.getType());
        List<CrossFiveHeroPatrons> allPatronsList = getTopNumPatronsList(config.getMakePvpTopPatronsNum());
        Map<Integer,List<CrossFiveHeroPatrons>> patronsMap = makePatronsMapV5(typeConfig.getPveUserPerList(),typeConfig.getPvePatronsWeightList(),allPatronsList);
        Map<Integer,List<CrossFiveHeroPatrons>> copySelectMap = copySelectMap(patronsMap);
        for(FiveHeroOrderConfig orderConfig : orderMap.values()){
            CrossFiveHeroToken token = new CrossFiveHeroToken();
            token.setTokenId(orderConfig.getId());
            token.setBattleTimes(0);
            token.setValue(0);
            CrossFiveHeroPatrons p = getOnePatrons(typeConfig.getPvePatronsWeightList(),copySelectMap);
            if(p == null){
                //没人了就重置池子再来
                copySelectMap = copySelectMap(patronsMap);
                p = getOnePatrons(typeConfig.getPvpPatronsWeightList(),copySelectMap);
                if(p == null){
                    logger.debug("五熊争霸，他妈炸了啊");
                    break;
                }
            }
            token.setDefPatrons(makeBattlePatrons(p,orderConfig.getId()));
            tokenMap.put(token.getTokenId(),token);
        }
        return tokenMap;
    }

    private CrossFiveHeroBattlePatrons makeBattlePatrons(CrossFiveHeroPatrons p,int index){
        CrossFiveHeroBattlePatrons battlePatrons = new CrossFiveHeroBattlePatrons();
        battlePatrons.setId(p.getId());
        battlePatrons.setIndex(index);
        battlePatrons.setUserId(p.getUserId());
        battlePatrons.setAbility(p.getAbility());
        battlePatrons.setMaxBlood(p.getAbility());
        battlePatrons.setNowBlood(p.getAbility());
        battlePatrons.setSkin(p.getSkin());
        return battlePatrons;
    }

    public void initData() {
        makeMap();
        chatLogic = new CrossFiveHeroChatLogic(getActivityInfo(),config.getChatNum());
        initAllRankList();
    }

    public void initFromDbData() {
        chatLogic = new CrossFiveHeroChatLogic(getActivityInfo(),config.getChatNum());
        initAllRankList();
    }
    
    private boolean isAble(CrossFiveHeroUserData userData) {
        return userData.getCampId() != 0;
    }

    /**
     * 初始化全部榜单
     */
    private void initAllRankList() {
        CrossFiveHeroRankListModel userModel = new CrossFiveHeroRankListModel();
        Map<Integer, CrossFiveHeroRankListModel> campUserMap = new ConcurrentHashMap<>();
        Map<Integer, CrossFiveHeroRankListModel> campUnionMap = new ConcurrentHashMap<>();

        for (CrossFiveHeroUserData userData : userDataMap.values()) {
            if (isAble(userData) && userData.getIntegral() > 0) {
                CrossFiveHeroRank rank = new CrossFiveHeroRank(String.valueOf(userData.getUserId()), userData.getIntegral(), userData.getIntegralTime());
                // 【个人榜】
                userModel.rankChange(rank);
                // 【阵营内个人榜】
                campUserMap.putIfAbsent(userData.getCampId(), new CrossFiveHeroRankListModel());
                campUserMap.get(userData.getCampId()).rankChange(rank);
            }
        }


        for (CrossFiveHeroUnion join : unionMap.values()) {
            if (join.getCampId() != 0) {
                // 【阵营内商会榜】
                campUnionMap.putIfAbsent(join.getCampId(), new CrossFiveHeroRankListModel());
                CrossFiveHeroRank rank = getUnionPopularityRank(join);
                campUnionMap.get(join.getCampId()).rankChange(rank);
            }
        }

        userRank = userModel;
        campUserRankMap = campUserMap;
        campUnionRankMap = campUnionMap;
    }

    private CrossFiveHeroRank getUnionPopularityRank(CrossFiveHeroUnion join) {
        long unionValue = 0;
        long maxTime = 0;
        for (long memberId : join.getMemberMap().keySet()) {
            CrossFiveHeroUserData memberData = getUserData(memberId);
            unionValue += memberData.getIntegral();
            maxTime = Math.max(maxTime, memberData.getIntegral());
        }

        CrossFiveHeroRank rank = new CrossFiveHeroRank(join.getUnionUid(), unionValue, maxTime);
        if (join.getTotalAbility() == 0L) {
            join.reCalcAbility();
        }
        rank.setAbility(join.getTotalAbility());

        return rank;
    }
    //
    private void logPvp(){
        Map<Integer,List<CrossFiveHeroPatrons>> pOccMap = new ConcurrentHashMap<>();
        List<CrossFiveHeroPatrons> allPatronsList = getAllTopNumOccPatronsList(config.getMakePvpTopPatronsNum());
        for(CrossFiveHeroPatrons patrons : allPatronsList){
            PatronsInfo patronsInfo = PatronsMgr.getPatronsInfo(patrons.getId());
            if(!pOccMap.containsKey(patronsInfo.getOccupation())){
                pOccMap.put(patronsInfo.getOccupation(),new ArrayList<>());
            }
            pOccMap.get(patronsInfo.getOccupation()).add(patrons);
        }
        logger.debug("所有门客数:");
        for(int occId : pOccMap.keySet()){
            logger.debug("职业{}，门客数{}",occId,pOccMap.get(occId).size());
        }
    }
    //生成地图
    private void makeMap(){
        logPvp();

        Map<Integer, CrossFiveHeroCity> cityMap = new ConcurrentHashMap<>();
        //山贼
        logger.debug("山贼生成");
        Map<Integer,BigInteger> pAMap = new ConcurrentHashMap<>();
        List<CrossFiveHeroPatrons> allPatronsList = getAllTopNumOccPatronsList(config.getMakeBanditTopPatronsNum());
        logger.debug("山贼用到的所有门客");
        for(CrossFiveHeroPatrons patrons : allPatronsList){
            PatronsInfo patronsInfo = PatronsMgr.getPatronsInfo(patrons.getId());
            BigInteger allValue = pAMap.getOrDefault(patronsInfo.getOccupation(),BigInteger.ZERO);
            allValue = allValue.add(BigInteger.valueOf(patrons.getAbility()));
            pAMap.put(patronsInfo.getOccupation(),allValue);
//            logger.debug("userId{},patronsId{},能力:{},职业{}",patrons.getUserId(),patrons.getId(),patrons.getAbility(),patronsInfo.getOccupation());
        }
        //山贼所在城池没有职业的时候是前六门客总能力除于人数
        List<CrossFiveHeroPatrons> zeroPatronMap = getTopNumPatronsList(config.getMakeBanditTopPatronsNum());
        for(CrossFiveHeroPatrons p : zeroPatronMap){
            BigInteger allValue = pAMap.getOrDefault(0,BigInteger.ZERO);
            allValue = allValue.add(BigInteger.valueOf(p.getAbility()));
            pAMap.put(0,allValue);
        }
        for(int occId : pAMap.keySet()){
            BigInteger value = pAMap.get(occId);
            pAMap.put(occId,value.divide(BigInteger.valueOf(userDataMap.size())));
        }
        logger.debug("山贼用到的所有门客加起来后的职业总能力");
        for(int occId : pAMap.keySet()){
            logger.debug("职业{}，能力平局值，总和/人数={}",occId,pAMap.get(occId));
        }
        for(FiveHeroCityConfig cityConfig : config.getCityConfigMap().values()){
            CrossFiveHeroCity city = new CrossFiveHeroCity();
            city.setActivityId(config.getActivityId());
            city.setGroupId(groupId);
            city.setCityId(cityConfig.getId());
            city.setCampId(cityConfig.getInitialCamp());
            //主城没法打，不用生产兵
            if(cityConfig.getType() == 4){
                Map<Integer,CrossFiveHeroToken> tokenMap = getRandomTokenLuoYang(cityConfig);
                city.setDefTokenMap(tokenMap);
            }else if(cityConfig.getType() != 5){
                Map<Integer,CrossFiveHeroBattlePatrons> rpMap = getRandomPatronsPveV2(cityConfig);
                city.setDefPatronsMap(rpMap);
                //todo-xx 血量
                if(cityConfig.getType() <= 3){
                    FiveHeroTypeConfig typeConfig = config.getTypeConfig(cityConfig.getType());
                    Map<Long, Integer> killCountMap = city.getKillCountMap();
                    killCountMap.put(1L,typeConfig.getBloodList().get(0));
                }
            }else{
                city.setDefPatronsMap(new ConcurrentHashMap<>());
            }

            Map<Integer, CrossFiveHeroBandit> banditMap = new ConcurrentHashMap<>();
            FiveHeroTypeConfig typeConfig = config.getTypeConfig(cityConfig.getType());
            for(int eventId : typeConfig.getEventMap().keySet()){
                FiveHeroEventConfig eventConfig = config.getEventConfig(eventId);
                List<Integer> pList = eventConfig.getParameterList();
                if(eventConfig.getType() == eFiveHeroEventType.Bandit.getValue()){
                    int occId = cityConfig.getJobBuffEffectList().get(0);
                    CrossFiveHeroBandit bandit = new CrossFiveHeroBandit();
                    bandit.setCityId(cityConfig.getId());
                    bandit.setDieCount(0);
                    bandit.setBanditId(pList.get(0));
                    BigInteger blood = pAMap.get(occId).multiply(BigInteger.valueOf(pList.get(1))).divide(BigInteger.valueOf(1000));
                    bandit.setMaxBlood(blood);
                    bandit.setBlood(blood);
                    banditMap.put(bandit.getBanditId(),bandit);
                }
            }
            city.setBanditMap(banditMap);
            cityMap.put(city.getCityId(),city);
            addNeedInsertCityData(city);
        }
        crossFiveHeroMatchData.setCityMap(cityMap);
        logger.debug("初始化城市完成");
    }
    // ============================== 发消息 ==============================

    protected void sendPacket(int code, AbstractMessage.Builder<?> messageBuilder, long userId) {
        UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(userId);
        if (userBaseInfo == null) {
            return;
        }
        YanQuMessage message = YanQuMessageUtils.buildMessage(code, messageBuilder);
        MessageHelper.sendPacket(userBaseInfo.getServerId(), userId, message);
    }

    //下发门客的职业对应能力值
    private List<Long> getUserOccPatronsAbility(long userId){
        Map<Integer,Long> occAbMap = new ConcurrentHashMap<>();
        //五个职业
        for(int occ = 1; occ <= 5 ; occ++){
            occAbMap.put(occ,0L);
        }
        CrossFiveHeroUserData userData = getUserData(userId);
        Map<Integer, CrossFiveHeroPatrons> patronsMap = userData.getPatronsMap();
        for(CrossFiveHeroPatrons patrons : patronsMap.values()){
            PatronsInfo patronsInfo = PatronsMgr.getPatronsInfo(patrons.getId());
            occAbMap.put(patronsInfo.getOccupation(),occAbMap.getOrDefault(patronsInfo.getOccupation(),0L) + getPatronsMaxBlood(patrons));
        }
        List<Long> gagaList = new ArrayList<>();
        for(int occ = 1; occ <= 5 ; occ++){
            gagaList.add(occAbMap.get(occ));
        }
        return gagaList;
    }

    public void syncUserDataMsg(long userId){
        CrossFiveHeroUserData userData = getUserData(userId);
        if(userData != null){
            FiveHeroProto.FiveHeroSyncUserDataMsg.Builder syncMsg = FiveHeroProto.FiveHeroSyncUserDataMsg.newBuilder();
            syncMsg.setActivityId(getActivityInfo().getActivityId());
            syncMsg.setUserId(userId);
            syncMsg.setPopularity(userData.getIntegral());
            syncMsg.setHp(userData.getHp());
            syncMsg.setHpTime((int)(userData.getHpTime()/1000));
            syncMsg.setCampId(userData.getCampId());
            syncMsg.setRank(getUserRankNum(userId));
            syncMsg.setExp(crossFiveHeroMatchData.getExpMap().getOrDefault(userData.getCampId(),0));
            syncMsg.addAllPBaseAbility(getUserOccPatronsAbility(userId));
            syncMsg.setAttackLuoYangTimes(userData.getLuoYangAttTimes());
            sendPacket(ClientProtocol.U_FIVEHERO_USER_DATA_SYNC, syncMsg, userId);
        }else{
            FiveHeroProto.FiveHeroSyncUserDataMsg.Builder syncMsg = FiveHeroProto.FiveHeroSyncUserDataMsg.newBuilder();
            syncMsg.setActivityId(getActivityInfo().getActivityId());
            syncMsg.setUserId(userId);
            syncMsg.setPopularity(0);
            syncMsg.setHp(0);
            syncMsg.setRank(0);
            syncMsg.setHpTime(0);
            syncMsg.setCampId(0);
            syncMsg.setExp(0);
            syncMsg.setAttackLuoYangTimes(0);
            sendPacket(ClientProtocol.U_FIVEHERO_USER_DATA_SYNC, syncMsg, userId);
        }
    }

    //升级了导致战力变化了要同步
    public void syncUserDataMsg(long userId,long addZhanli){
        CrossFiveHeroUserData userData = getUserData(userId);
        if(userData != null){
            FiveHeroProto.FiveHeroSyncUserDataMsg.Builder syncMsg = FiveHeroProto.FiveHeroSyncUserDataMsg.newBuilder();
            syncMsg.setActivityId(getActivityInfo().getActivityId());
            syncMsg.setUserId(userId);
            syncMsg.setPopularity(userData.getIntegral());
            syncMsg.setHp(userData.getHp());
            syncMsg.setHpTime((int)(userData.getHpTime()/1000));
            syncMsg.setCampId(userData.getCampId());
            syncMsg.setRank(getUserRankNum(userId));
            syncMsg.setExp(crossFiveHeroMatchData.getExpMap().getOrDefault(userData.getCampId(),0));
            syncMsg.addAllPBaseAbility(getUserOccPatronsAbility(userId));
            syncMsg.setAttackLuoYangTimes(userData.getLuoYangAttTimes());
            syncMsg.setAddZhanli(addZhanli + "");
            sendPacket(ClientProtocol.U_FIVEHERO_USER_DATA_SYNC, syncMsg, userId);
        }else{
            FiveHeroProto.FiveHeroSyncUserDataMsg.Builder syncMsg = FiveHeroProto.FiveHeroSyncUserDataMsg.newBuilder();
            syncMsg.setActivityId(getActivityInfo().getActivityId());
            syncMsg.setUserId(userId);
            syncMsg.setPopularity(0);
            syncMsg.setHp(0);
            syncMsg.setRank(0);
            syncMsg.setHpTime(0);
            syncMsg.setCampId(0);
            syncMsg.setExp(0);
            syncMsg.setAttackLuoYangTimes(0);
            sendPacket(ClientProtocol.U_FIVEHERO_USER_DATA_SYNC, syncMsg, userId);
        }
    }

    //获取门客的总战力
    private long getUserPatronsAb(long userId){
        CrossFiveHeroUserData userData = getUserData(userId);
        long value = 0;
        for(CrossFiveHeroPatrons p : userData.getPatronsMap().values()){
            value = value + p.getAbility();
        }
        return value;
    }

    private long getMaxAbUserId(List<Long> battleUserIdList){
        LinkedList<CrossFiveHeroRank> rankList = new LinkedList<>();
        for(long userId : battleUserIdList){
            CrossFiveHeroRank rank = new CrossFiveHeroRank(userId + "" ,getUserPatronsAb(userId),0L);
            rankList.add(rank);
        }
        rankList.sort(new CrossFiveHeroRankSort());
        if(rankList.size() > 0){
            CrossFiveHeroRank fRank = rankList.getFirst();
            return Long.valueOf(fRank.getId());
        }
        return 0;
    }


    private FiveHeroProto.FiveHeroCityMsg.Builder parseFiveHeroCityMsg(CrossFiveHeroCity city){
        FiveHeroProto.FiveHeroCityMsg.Builder cityMsg = FiveHeroProto.FiveHeroCityMsg.newBuilder();
        cityMsg.setCityId(city.getCityId());
        cityMsg.setCampId(city.getCampId());
        cityMsg.setUserNum(cityBattleUserIdMap.getOrDefault(city.getCityId(),new ConcurrentHashMap<>()).size());
        List<Integer> flagList = new ArrayList<>();
        List<Long> battleUserIdList = new ArrayList<>();
        if(cityBattleUserIdMap.containsKey(city.getCityId())){
            battleUserIdList = new ArrayList<>(cityBattleUserIdMap.get(city.getCityId()).keySet());
            for(long battleUserId : battleUserIdList){
                CrossFiveHeroUserData battleUserData = getUserData(battleUserId);
                if(battleUserData != null && battleUserData.getCampId() > 0 && !flagList.contains(battleUserData.getCampId())){
                    flagList.add(battleUserData.getCampId());
                }
            }
            if(flagList.size() > 0){
                cityMsg.addAllFlags(flagList);
            }
        }
        FiveHeroProto.FiveHeroSimpleUserInfoMsg.Builder simpleUserMsg = FiveHeroProto.FiveHeroSimpleUserInfoMsg.newBuilder();
        UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(getMaxAbUserId(battleUserIdList));
        if(userBaseInfo != null){
            simpleUserMsg.setUserId(city.getOccUserId());
            simpleUserMsg.setServerId(userBaseInfo.getServerId());
            simpleUserMsg.setNickName(userBaseInfo.getNickName());
            simpleUserMsg.setDecoration(userBaseInfo.getDecoration());
        }
        cityMsg.setBigUser(simpleUserMsg);

        FiveHeroCityConfig cityConfig = config.getCityConfig(city.getCityId());
        if(cityConfig != null && cityConfig.getType() == 5){
            Map<Integer, Integer> expMap = crossFiveHeroMatchData.getExpMap();
            cityMsg.setExp(expMap.getOrDefault(cityConfig.getInitialCamp(),0));

        }
        return cityMsg;
    }

    public void enterMap(long userId, FiveHeroProto.FiveHeroEnterReqMsg reqMsg) {
        synchronized (inEnterUserIdList){
            if(!reqMsg.getEnter()){
                //不用校验了。每晚都会清掉
                inEnterUserIdList.remove(userId);
                return;
            }
            if(!inEnterUserIdList.contains(userId)){
                inEnterUserIdList.add(userId);
            }
        }
        FiveHeroProto.FiveHeroEnterRespMsg.Builder builder = FiveHeroProto.FiveHeroEnterRespMsg.newBuilder();
        builder.setRet(0);
        for(CrossFiveHeroCity city : crossFiveHeroMatchData.getCityMap().values()){
            builder.addCity(parseFiveHeroCityMsg(city));
        }
        sendPacket(ClientProtocol.U_FIVEHERO_ENTER_DATA, builder, userId);
    }

    //获取占领城池的积分
    private int getTodayTypeCityIntegral(int type, int campId){
        int value = 0;
        Map<Integer, CrossFiveHeroCity>  cityMap = crossFiveHeroMatchData.getCityMap();
        for(CrossFiveHeroCity city : cityMap.values()){
            FiveHeroCityConfig cityConfig = config.getCityConfig(city.getCityId());
            if(campId == city.getCampId() && cityConfig.getType() == type){
                FiveHeroTypeConfig typeConfig = config.getTypeConfig(type);
                value = value + typeConfig.getCampScore();
            }
        }
        return value;
    }

    public void getCity(long userId, FiveHeroProto.FiveHeroGetCityReqMsg reqMsg) {
        Map<Integer,Map<Integer,Integer>> distanceMap = FiveHeroMapLogic.getCityDistanceMap(config.getCityConfigMap());
        Map<Integer,Integer> campdistanceMap = distanceMap.get(reqMsg.getCityId());
        CrossFiveHeroUserData userData = getUserData(userId);
        int cityId = reqMsg.getCityId();
        Map<Integer, CrossFiveHeroCity> cityMap = crossFiveHeroMatchData.getCityMap();
        if(cityMap.containsKey(cityId)){
            CrossFiveHeroCity city = cityMap.get(cityId);
            FiveHeroProto.FiveHeroGetCityRespMsg.Builder builder = FiveHeroProto.FiveHeroGetCityRespMsg.newBuilder();
            builder.setDistance(campdistanceMap.getOrDefault(userData.getCampId(),0));
            builder.setCampId(city.getCampId());
            builder.setCampIntegral((int)getCampScore(city.getCampId()));
            //todo-xx 血量
            builder.setDefNum(city.getKillCountMap().getOrDefault(1L,0));
            builder.setCanBattle(checkCanDo(cityId,userData.getCampId()));
//            builder.setCanBattle(true);
            /*if(cityId == config.getLuoYangId()){
                long nowTime = System.currentTimeMillis();
                if(nowTime < config.getTodayInSideBeginTime() || nowTime > config.getTodayInSideOverTime()){
                   builder.setCanBattle(false);
                }else{
                    builder.setCanBattle(checkCanDo(cityId,userData.getCampId()));
                }
            }else{
                builder.setCanBattle(checkCanDo(cityId,userData.getCampId()));
            }*/
            if(city.getOccUserId() != 0){
                UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(city.getOccUserId());
                if(userBaseInfo != null){
                    builder.setUser(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
                }
            }
            FiveHeroCityConfig cityConfig = config.getCityConfig(cityId);
            if(cityConfig.getType() == 5){
                builder.setType1Integral(getTodayTypeCityIntegral(1,city.getCampId()));
                builder.setType2Integral(getTodayTypeCityIntegral(2,city.getCampId()));
                builder.setType3Integral(getTodayTypeCityIntegral(3,city.getCampId()));
                Map<Integer, Map<Integer, Long>> scoreMap = crossFiveHeroMatchData.getScoreTokenMap();
                Map<Integer, Long> dayScoreMap = scoreMap.getOrDefault(cityConfig.getInitialCamp(),new ConcurrentHashMap<>());
                long tokenValue = 0;
                for(long value : dayScoreMap.values()){
                    tokenValue = tokenValue + value;
                }
                builder.setType4Integral((int)tokenValue);
                builder.setExp(crossFiveHeroMatchData.getExpMap().getOrDefault(city.getCampId(),0));
                builder.setExpAdd(getCampExpSpeed(city.getCampId()));
                long topUserId = getTopCampRankUser(city.getCampId());
                UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(topUserId);
                if(userBaseInfo != null){
                    builder.setBestMan(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
                    builder.setBeatManUserId(topUserId);
                }
                CrossFiveHeroUserData topUserData = getUserData(topUserId);
                if(topUserData != null){
                    builder.setPopularity((int)topUserData.getIntegral());
                }else{
                    builder.setPopularity(0);
                }
            }

            sendPacket(ClientProtocol.U_FIVEHERO_GET_CITY, builder, userId);
        }
    }

    //获取城市的商会个数
    private List<String> getCampUnionNum(int cityId){
        List<String> unionIdList = new ArrayList<>();
        Map<Long,Integer> userMap = new ConcurrentHashMap<>(cityBattleUserIdMap.get(cityId));
        for(long userId : userMap.keySet()){
            CrossFiveHeroUserData userData = getUserData(userId);
            if(!unionIdList.contains(userData.getUnionUid())){
                unionIdList.add(userData.getUnionUid());
            }
        }
        return unionIdList;
    }
    private List<Long> getCampUserNum(int cityId,int campId){
        List<Long> userIdList = new ArrayList<>();
        Map<Long,Integer> userMap = new ConcurrentHashMap<>(cityBattleUserIdMap.get(cityId));
        for(long userId : userMap.keySet()){
            CrossFiveHeroUserData userData = getUserData(userId);
            if(userData.getCampId() == campId){
                if(!userIdList.contains(userId)){
                    userIdList.add(userId);
                }
            }
        }
        return userIdList;
    }

    public void enterCity(long userId, FiveHeroProto.FiveHeroEnterCityReqMsg reqMsg) {
        FiveHeroProto.FiveHeroEnterCityRespMsg.Builder respMsg = FiveHeroProto.FiveHeroEnterCityRespMsg.newBuilder();
        respMsg.setRet(0);
        int cityId = reqMsg.getCityId();
        int ret = checkPublicBattle(cityId);
        if(ret != 0){
            respMsg.setRet(ret);
            sendPacket(ClientProtocol.U_FIVEHERO_ENTER_CITY, respMsg, userId);
            return;
        }
        //进去一个地方，其他地方都清理掉先
        for(int oCityId : cityBattleUserIdMap.keySet()){
            if(oCityId == cityId)continue;
            List<Long> userIdMap = new ArrayList<>(cityBattleUserIdMap.get(oCityId).keySet());
            if(userIdMap.contains(userId)){
                cityBattleUserIdMap.get(oCityId).remove(userId);
                CrossSceneMgr.quitScene(userId, System.currentTimeMillis());
                addCityChange(oCityId);
            }
        }
        if(cityId == 0){
            sendPacket(ClientProtocol.U_FIVEHERO_ENTER_CITY, respMsg, userId);
            return;
        }
        Map<Integer, CrossFiveHeroCity> cityMap = crossFiveHeroMatchData.getCityMap();
        if(!cityMap.containsKey(cityId)){
            return;
        }
        CrossFiveHeroCity city = cityMap.get(cityId);
        CrossFiveHeroUserData userData = getUserData(userId);
        //有资格的玩家才进入城市变成战斗状态
        if(userData != null && userData.getCampId() != 0){
            if(!cityBattleUserIdMap.containsKey(cityId)){
                cityBattleUserIdMap.put(cityId,new ConcurrentHashMap<>());
            }
            if(!cityBattleUserIdMap.get(cityId).containsKey(userId)){
                cityBattleUserIdMap.get(cityId).put(userId,city.getCampId());
                addCityChange(cityId);
            }
            if(userData.getServerId() == 0){
                UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(userId);
                if(userBaseInfo != null){
                    userData.setServerId(userBaseInfo.getServerId());
                }
            }
        }

        respMsg.setCampId(city.getCampId());
//        respMsg.setPatronsValue(getOccPatronsAbAll(userId,city).toString());
        respMsg.setPatronsValue(getAllPatronsBlood(userId,city) + "");
        respMsg.setPopularity(0);
        respMsg.setUserNum(0);
        respMsg.setCampUnionNum(0);
        //todo-xx 血量
        respMsg.setDefNum(city.getKillCountMap().getOrDefault(1L,0));
        if(userData != null){
            if(cityBattleUserIdMap.containsKey(cityId)){
                respMsg.setUserNum(cityBattleUserIdMap.get(cityId).size());
            }
            respMsg.setPopularity(userData.getIntegral());
            respMsg.setCampUnionNum(getCampUserNum(cityId,userData.getCampId()).size());
            FiveHeroCityConfig cityConfig = config.getCityConfig(cityId);
            if(cityConfig.getType() == 4){
                respMsg.setTokenNum(getUserTokenList(userId).size());
                respMsg.setScoreSpeed(getCampScoreSpeed(userData.getCampId()));
                respMsg.setCampTokenNum(getCampTokenList(userData.getCampId()).size());
                //排行榜的
                respMsg.setRank(getUserTokenRankNum(userId));
                int rankNum = 0;
                for(CrossFiveHeroRank rank : getUserTokenRankTop3(userId)){
                    rankNum++;
                    respMsg.addRankList(parseFiveHeroUserRankMsg(rank,rankNum));
                }
            }
            CrossFiveHeroPatrons patrons = getUserTopCityPatrons(userId,city);
            if(patrons != null){
                respMsg.setPatronsId(patrons.getId());
                respMsg.setPatronsAtt(String.valueOf(getPatronsMaxBlood(patrons)));
            }else{
                respMsg.setPatronsId(0);
                respMsg.setPatronsAtt("0");
            }
        }
        sendPacket(ClientProtocol.U_FIVEHERO_ENTER_CITY, respMsg, userId);

    }

    //获取自己阵营的总积分
    private long getCampScore(int campId){
        Map<Integer, Long> scoreMap = crossFiveHeroMatchData.getScoreMap();
        long value = scoreMap.getOrDefault(campId,0L);
        Map<Integer, CrossFiveHeroCity> cityMap = crossFiveHeroMatchData.getCityMap();
        for(CrossFiveHeroCity city : cityMap.values()){
            if(city.getCampId() == campId){
                FiveHeroCityConfig cityConfig = config.getCityConfig(city.getCityId());
                FiveHeroTypeConfig typeConfig = config.getTypeConfig(cityConfig.getType());
                value = value + typeConfig.getCampScore();
            }
        }
        return value;
    }
    //获得今日的占领产出积分
    private long getCampTodayTokenScore(int campId){
        int matchDay = config.getMatchDay();
        Map<Integer, Map<Integer, Long>> scoreMap = crossFiveHeroMatchData.getScoreTokenMap();
        Map<Integer, Long> dayScoreMap = scoreMap.getOrDefault(campId,new ConcurrentHashMap<>());
        return dayScoreMap.getOrDefault(matchDay,0L);
    }

    private Map<Integer,Map<Integer,Long>> getCampScoreMap(){
        Map<Integer,Map<Integer,Long>> campScoreMap = new ConcurrentHashMap<>();
        Map<Integer, CrossFiveHeroCity> cityMap = crossFiveHeroMatchData.getCityMap();
        for(CrossFiveHeroCity city : cityMap.values()){
            if(city.getCampId() == 0){
                continue;
            }
            FiveHeroCityConfig cityConfig = config.getCityConfig(city.getCityId());
            FiveHeroTypeConfig typeConfig = config.getTypeConfig(cityConfig.getType());
            if(!campScoreMap.containsKey(city.getCampId())){
                campScoreMap.put(city.getCampId(),new ConcurrentHashMap<>());
            }
            campScoreMap.get(city.getCampId()).put(city.getCityId(),(long)typeConfig.getCampScore());
        }
        return campScoreMap;
    }

    //获取阵营总声望
    private long getCampPopularity(int campId){
        long value = 0;
        for(CrossFiveHeroUserData userData : userDataMap.values()){
            if(userData.getCampId() == campId){
                value += userData.getIntegral();
            }
        }
        return value;
    }

    private long getCampPopularityTime(int campId){
        long time = 0;
        for(CrossFiveHeroUserData userData : userDataMap.values()){
            if(userData.getCampId() == campId){
                if(userData.getIntegralTime() > time){
                    time = userData.getIntegralTime();
                }
            }
        }
        return time;
    }

    //获取自己阵营的积分速度
    private int getCampScoreSpeed(long campId){
        int luoyangId = config.getLuoYangId();
        Map<Integer, CrossFiveHeroCity> cityMap = crossFiveHeroMatchData.getCityMap();
        CrossFiveHeroCity city = cityMap.get(luoyangId);
        int addValue = 0;
        if(city != null){
            Map<Integer, CrossFiveHeroToken> tokenMap = city.getDefTokenMap();
            for(CrossFiveHeroToken token : tokenMap.values()){
                if(token.getCampId() == campId){
                    FiveHeroOrderConfig fiveHeroOrderConfig = config.getOrderConfig(token.getTokenId());
                    addValue = addValue + fiveHeroOrderConfig.getRecoverNum();
                }
            }
        }
        return addValue;
    }

    //获得阵营的经验值速度
    private int getCampExpSpeed(long campId){
        Map<Integer, CrossFiveHeroCity> cityMap = crossFiveHeroMatchData.getCityMap();
        int addValue = 0;
        for(CrossFiveHeroCity city : cityMap.values()){
            if(city.getCampId() == campId){
                FiveHeroCityConfig cityConfig = config.getCityConfig(city.getCityId());
                FiveHeroTypeConfig typeConfig = config.getTypeConfig(cityConfig.getType());
                addValue = addValue + typeConfig.getCampPoint();
            }
        }
        return addValue;
    }
    private int cityExpAdd(CrossFiveHeroCity city){
        long addTime = DateHelper.MINUTE_MILLIONS;
        long nowTime = System.currentTimeMillis();
        int addValue = 0;
        synchronized (getCityPvpLock(city.getCityId())){
            long cutTime = nowTime - city.getExpAddTime();
            if(city.getCampId() != 0 && cutTime >= addTime){
                FiveHeroCityConfig cityConfig = config.getCityConfig(city.getCityId());
                FiveHeroTypeConfig typeConfig = config.getTypeConfig(cityConfig.getType());
                if(city.getExpAddTime() == 0 && typeConfig.getCampPoint() != 0){
                    logger.debug("炸了啊啊啊啊啊啊啊");
                }
                //主城没有加，直接略过
                if(typeConfig.getCampPoint() == 0){
                    return 0;
                }
                int addTimes = (int)(cutTime/addTime);
                addValue = addTimes * typeConfig.getCampPoint();
                city.setExpAddTime(city.getExpAddTime() + addTimes * addTime);
                addNeedUpdateCityData(city);
            }
        }
        return addValue;
    }
    //晚上结束了不叫exp，直接设置成明天开始时间
    private void setMingtianExpTime(){
        long ttime = config.getTomorrowInSideBeginTime();
        if(ttime == 0){
            return;
        }
        Map<Integer, CrossFiveHeroCity> cityMap = crossFiveHeroMatchData.getCityMap();
        for(CrossFiveHeroCity city : cityMap.values()){
            if(city.getExpAddTime() == ttime)continue;
            city.setExpAddTime(ttime);
            addNeedUpdateCityData(city);
        }

    }
    //获取所有阵营的加成Exp加了多少 汉就不加了
    private Map<Integer,Map<Integer,Integer>> getCampExpAddMap(){
        Map<Integer, CrossFiveHeroCity> cityMap = crossFiveHeroMatchData.getCityMap();
        Map<Integer,Map<Integer,Integer>> addValueMap = new ConcurrentHashMap<>();
        for(CrossFiveHeroCity city : cityMap.values()){
            int campId = city.getCampId();
            int addValue = cityExpAdd(city);
            if(addValue > 0){
                if(!addValueMap.containsKey(campId)){
                    addValueMap.put(campId,new ConcurrentHashMap<>());
                }
                addValueMap.get(campId).put(city.getCityId(),addValue);
            }
        }
        return addValueMap;
    }

    private CrossFiveHeroCity getLuoYangCity(){
        int luoyangId = config.getLuoYangId();
        Map<Integer, CrossFiveHeroCity> cityMap = crossFiveHeroMatchData.getCityMap();
        CrossFiveHeroCity city = cityMap.get(luoyangId);
        return city;
    }
    //获取自己的城主令
    private List<CrossFiveHeroToken> getUserTokenList(long userId){
        CrossFiveHeroCity city = getLuoYangCity();
        List<CrossFiveHeroToken> list = new ArrayList<>();
        if(city != null){
            Map<Integer, CrossFiveHeroToken> tokenMap = city.getDefTokenMap();
            for(CrossFiveHeroToken token : tokenMap.values()){
                if(token.getCampId() != 0){
                    if(token.getDefPatrons().getUserId() == userId){
                        list.add(token);
                    }
                }
            }
        }
        return list;
    }

    private Map<Long,List<CrossFiveHeroToken>> getUserTokenMap(){
        int luoyangId = config.getLuoYangId();
        Map<Integer, CrossFiveHeroCity> cityMap = crossFiveHeroMatchData.getCityMap();
        CrossFiveHeroCity city = cityMap.get(luoyangId);
        Map<Long,List<CrossFiveHeroToken>> map = new ConcurrentHashMap<>();
        if(city != null){
            Map<Integer, CrossFiveHeroToken> tokenMap = city.getDefTokenMap();
            for(CrossFiveHeroToken token : tokenMap.values()){
                if(token.getCampId() != 0){
                    long tokenUserId = token.getDefPatrons().getUserId();
                    if(!map.containsKey(tokenUserId)){
                        map.put(tokenUserId,new ArrayList<>());
                    }
                    map.get(tokenUserId).add(token);
                }
            }
        }
        return map;
    }

    private List<CrossFiveHeroToken> getCampTokenList(long campId){
        List<CrossFiveHeroToken> list = new ArrayList<>();
        int luoyangId = config.getLuoYangId();
        Map<Integer, CrossFiveHeroCity> cityMap = crossFiveHeroMatchData.getCityMap();
        CrossFiveHeroCity city = cityMap.get(luoyangId);
        if(city != null){
            Map<Integer, CrossFiveHeroToken> tokenMap = city.getDefTokenMap();
            for(CrossFiveHeroToken token : tokenMap.values()){
                if(token.getCampId() == campId){
                    list.add(token);
                }
            }
        }
        return list;
    }




    //获取对应门客的最大赚钱
    public long getPatronsMaxBlood(CrossFiveHeroPatrons patrons){
        BigDecimal abValue = BigDecimal.valueOf(patrons.getAbility());
        long addEvent = getItemAdd(patrons.getUserId());
        long addPerEvent = getItemPerAdd(patrons.getUserId());
        long addPerLevel = getCampLevelPerAdd(patrons.getUserId());
        long addPerSkill = getPatronSkillPerAdd(patrons.getUserId());
        if(Config.isDebug()){
            CrossFiveHeroMgr.getLogger().info("玩家{} 五熊门客 加成{}", patrons.getUserId(), addPerSkill);
        }
        abValue = abValue.multiply(
                BigDecimal.valueOf(1000).add(BigDecimal.valueOf(addPerEvent)).add(BigDecimal.valueOf(addPerLevel))
        ).divide(BigDecimal.valueOf(1000),2,BigDecimal.ROUND_UP);
        abValue = abValue.add(BigDecimal.valueOf(addEvent)).setScale(0,BigDecimal.ROUND_UP);
        abValue = abValue.multiply(BigDecimal.valueOf(1000 + addPerSkill)).divide(BigDecimal.valueOf(1000),0,BigDecimal.ROUND_UP);
        return abValue.longValue();
    }

    public long getPatronsMaxBloodNoSkill(CrossFiveHeroPatrons patrons){
        BigDecimal abValue = BigDecimal.valueOf(patrons.getAbility());
        long addEvent = getItemAdd(patrons.getUserId());
        long addPerEvent = getItemPerAdd(patrons.getUserId());
        long addPerLevel = getCampLevelPerAdd(patrons.getUserId());
        abValue = abValue.multiply(
                BigDecimal.valueOf(1000).add(BigDecimal.valueOf(addPerEvent)).add(BigDecimal.valueOf(addPerLevel))
        ).divide(BigDecimal.valueOf(1000),2,BigDecimal.ROUND_UP);
        abValue = abValue.add(BigDecimal.valueOf(addEvent)).setScale(0,BigDecimal.ROUND_UP);
        return abValue.longValue();
    }

    //获取门客加上城市的最大血量加成，这个是个护盾
    private long getPatronsMaxBloodShield(CrossFiveHeroPatrons patrons,CrossFiveHeroCity city){
        if(city != null){
            FiveHeroCityConfig cityConfig = config.getCityConfig(city.getCityId());
            List<Integer> jList = cityConfig.getJobBuffEffectList();
            PatronsInfo patronsInfo = PatronsMgr.getPatronsInfo(patrons.getId());
            BigDecimal mValue = BigDecimal.valueOf(1000);
            long addPerSkill = getPatronSkillPerAdd(patrons.getUserId());
            mValue = mValue.add(BigDecimal.valueOf(addPerSkill));
            if(jList.size() > 1 && jList.get(1) > 0 && patronsInfo.getOccupation() == jList.get(0)){
                mValue = mValue.add(BigDecimal.valueOf(jList.get(1)));
            }
            /*CrossFiveHeroUserData userData = getUserData(patrons.getUserId());
            if(jList.size() > 3 && jList.get(3) > 0 && userData != null && userData.getCampId() == jList.get(2)){
                mValue = mValue.add(BigDecimal.valueOf(jList.get(3)));
            }*/
            BigDecimal value = BigDecimal.valueOf(getPatronsMaxBloodNoSkill(patrons));
            value = value.multiply(mValue).divide(BigDecimal.valueOf(1000),0,BigDecimal.ROUND_UP);
            if(Config.isDebug()){
                CrossFiveHeroMgr.getLogger().info("五熊玩家{},门客 {}， 基础 {}， 加成 {}， 终值：{}", patrons.getUserId(), patrons.getId(), value.toString(), mValue, value.toString());
            }
            return value.longValue();
        }
        return getPatronsMaxBlood(patrons);
    }

    //获取护盾值
    private long getPatronsShieldValue(CrossFiveHeroPatrons patrons,CrossFiveHeroCity city){
        if(city == null){
            return 0;
        }
        FiveHeroCityConfig cityConfig = config.getCityConfig(city.getCityId());
        List<Integer> jList = cityConfig.getJobBuffEffectList();
        PatronsInfo patronsInfo = PatronsMgr.getPatronsInfo(patrons.getId());
        if(patronsInfo.getOccupation() == jList.get(0) && jList.size() > 1 && jList.get(1) > 0){
            return getPatronsMaxBlood(patrons) * jList.get(1) / 1000;
        }else{
            return 0;
        }
    }
    //门客加上护盾的血量
    private long getPatronsBloodShield(CrossFiveHeroPatrons patrons,CrossFiveHeroCity city){
        return getPatronsMaxBloodShield(patrons,city);
        //被改成不會掉血了，直接用最大血量，獲得道具沒有加血量了
//        return patrons.getNowBlood() + getPatronsShieldValue(patrons,city);
    }

    //阵营加成门客能力值 固定值加成
    private long getCampLevelAdd(long userId){
        checkExpAdd();
        Map<Integer, Integer> expMap = crossFiveHeroMatchData.getExpMap();
        CrossFiveHeroUserData userData = getUserData(userId);
        int expValue = 0;
        if(userData != null && userData.getCampId() != 0){
            if(expMap.containsKey(userData.getCampId())){
                expValue = expMap.get(userData.getCampId());
            }
        }
        int addValue = 0;
        if(expValue > 0){
            addValue = config.getTechAdd(expValue);
        }
        return addValue;
    }
    //百分比加成
    private long getCampLevelPerAdd(long userId){
        Map<Integer, Integer> expMap = crossFiveHeroMatchData.getExpMap();
        CrossFiveHeroUserData userData = getUserData(userId);
        int expValue = 0;
        if(userData != null && userData.getCampId() != 0){
            if(expMap.containsKey(userData.getCampId())){
                expValue = expMap.get(userData.getCampId());
            }
        }
        int addValue = 0;
        if(expValue >= 0){
            addValue = config.getTechPerthAdd(expValue);
        }
        return addValue;
    }

    private long getPatronSkillPerAdd(long userId){
        Map<Integer, Integer> expMap = crossFiveHeroMatchData.getExpMap();
        CrossFiveHeroUserData userData = getUserData(userId);
        int addValue = 0;
        for(CrossFiveHeroPatrons p : userData.getPatronsMap().values()){
            addValue = addValue + p.getAddPer();
        }
        addValue += userData.getCurioAddition();
        return addValue;
    }

    //事件加成到门客身上的能力值
    private long getEventAdd(CrossFiveHeroPatrons patrons){
        List<Long> addList = new ArrayList<>(patrons.getAddAbilityMap().values());
        long allAddValue = 0;
        for(long addValue : addList){
            allAddValue = allAddValue + addValue;
        }
        return allAddValue;
    }

    private long getEventPerAdd(CrossFiveHeroPatrons patrons){
        List<Long> addList = new ArrayList<>(patrons.getAddPercentageAbilityMap().values());
        long allAddValue = 0;
        for(long addValue : addList){
            allAddValue = allAddValue + addValue;
        }
        return allAddValue;
    }

    private long getItemAdd(long userId){
        CrossFiveHeroUserData userData = getUserData(userId);
        Map<Integer, Integer> itemNumMap = new ConcurrentHashMap<>(userData.getAddItemMap());
        long addValue = 0;
        for(int goodIds : itemNumMap.keySet()){
            GoodsInfo goodsInfo = GoodsMgr.getGoodsInfo(goodIds);
            long p0 = goodsInfo.getParamList().get(0).longValue();
            if(p0 != 0){
                addValue = addValue + p0 * itemNumMap.get(goodIds);
            }
        }
        return addValue;
    }

    private long getItemPerAdd(long userId){
        CrossFiveHeroUserData userData = getUserData(userId);
        Map<Integer, Integer> itemNumMap = new ConcurrentHashMap<>(userData.getAddItemMap());
        long addPerValue = 0;
        for(int goodIds : itemNumMap.keySet()){
            GoodsInfo goodsInfo = GoodsMgr.getGoodsInfo(goodIds);
            long p1 = goodsInfo.getParamList().get(1).longValue();
            if(p1 != 0){
                addPerValue = addPerValue + p1 * itemNumMap.get(goodIds);
            }
        }
        return addPerValue;
    }

    //所有加成的具体值
    private long getAcAllAddValue(long userId){
        return getAcAllAddValue(userId,new ConcurrentHashMap<>(),0);
    }

    //levelAddPer 升级加了多少百分比
    private long getAcAllAddValue(long userId,Map<Integer,Integer> addItemMap,long levelAddPer){
        CrossFiveHeroUserData userData = getUserData(userId);
        long campTechPerValue = getCampLevelPerAdd(userId);
        campTechPerValue = campTechPerValue - levelAddPer;
        Map<Integer, Integer> itemNumMap = new ConcurrentHashMap<>(userData.getAddItemMap());
        for(int itemId : addItemMap.keySet()){
            itemNumMap.put(itemId,itemNumMap.getOrDefault(itemId,0) + addItemMap.get(itemId));
        }
        long addValue = 0;
        long addPerValue = 0;
        for(int goodIds : itemNumMap.keySet()){
            GoodsInfo goodsInfo = GoodsMgr.getGoodsInfo(goodIds);
            long p0 = goodsInfo.getParamList().get(0).longValue();
            if(p0 != 0){
                addValue = addValue + p0 * itemNumMap.get(goodIds);
            }
            long p1 = goodsInfo.getParamList().get(1).longValue();
            if(p1 != 0){
                addPerValue = addPerValue + p1 * itemNumMap.get(goodIds);
            }
        }
        Map<Integer, CrossFiveHeroPatrons> pMap = new ConcurrentHashMap<>(userData.getPatronsMap());
        long allPatronsAb = 0;
        for(CrossFiveHeroPatrons patrons : pMap.values()){
            allPatronsAb = allPatronsAb + patrons.getAbility();
        }
        BigDecimal allAddAb = BigDecimal.valueOf(allPatronsAb);
        allAddAb = allAddAb.multiply(BigDecimal.valueOf(addPerValue).add(BigDecimal.valueOf(campTechPerValue))).divide(BigDecimal.valueOf(1000),0,BigDecimal.ROUND_UP);
        allAddAb = allAddAb.add(BigDecimal.valueOf(addValue).multiply(BigDecimal.valueOf(pMap.size())));

        return allAddAb.longValue();
    }

    //新增道具之后战力加成值的变化
    private long getAllAddValueAddItem(long userId,Map<Integer,Integer> addItemMap){
        if(addItemMap.size() == 0){
            return 0;
        }
        long oldValue = getAcAllAddValue(userId,new ConcurrentHashMap<>(),0);
        long newValue = getAcAllAddValue(userId,addItemMap,0);
        return newValue - oldValue;
    }

    public long getAllAddValuePatronsUp(long userId){
        long allValue = 0;
        List<Long> aList = getUserOccPatronsAbility(userId);
        for(long value : aList){
            allValue += value;
        }
        return allValue;
    }

    private long getAllAddValueLevelUp(long userId,int levelAddPer){
        if(levelAddPer == 0){
            return 0;
        }
        long oldValue = getAcAllAddValue(userId,new ConcurrentHashMap<>(),levelAddPer);
        long newValue = getAcAllAddValue(userId,new ConcurrentHashMap<>(),0);
        return newValue - oldValue;
    }

    private long getItemAddValue(long userId){
        CrossFiveHeroUserData userData = getUserData(userId);
        Map<Integer, Integer> itemNumMap = new ConcurrentHashMap<>(userData.getAddItemMap());
        long addValue = 0;
        long addPerValue = 0;
        for(int goodIds : itemNumMap.keySet()){
            GoodsInfo goodsInfo = GoodsMgr.getGoodsInfo(goodIds);
            long p0 = goodsInfo.getParamList().get(0).longValue();
            if(p0 != 0){
                addValue = addValue + p0 * itemNumMap.get(goodIds);
            }
        }
        Map<Integer, CrossFiveHeroPatrons> pMap = new ConcurrentHashMap<>(userData.getPatronsMap());
        return addValue * pMap.size();
    }

    //百分比战力加成值
    private long getItemPerAddValue(long userId){
        CrossFiveHeroUserData userData = getUserData(userId);
        Map<Integer, Integer> itemNumMap = new ConcurrentHashMap<>(userData.getAddItemMap());
        long addPerValue = 0;
        for(int goodIds : itemNumMap.keySet()){
            GoodsInfo goodsInfo = GoodsMgr.getGoodsInfo(goodIds);
            long p1 = goodsInfo.getParamList().get(1).longValue();
            if(p1 != 0){
                addPerValue = addPerValue + p1 * itemNumMap.get(goodIds);
            }
        }
        Map<Integer, CrossFiveHeroPatrons> pMap = new ConcurrentHashMap<>(userData.getPatronsMap());
        long allPatronsAb = 0;
        for(CrossFiveHeroPatrons patrons : pMap.values()){
            allPatronsAb = allPatronsAb + patrons.getAbility();
        }
        BigDecimal allAddAb = BigDecimal.valueOf(allPatronsAb);
        allAddAb = allAddAb.multiply(BigDecimal.valueOf(addPerValue)).divide(BigDecimal.valueOf(1000),0,BigDecimal.ROUND_UP);

        return allAddAb.longValue();
    }

    private long getCampLevelPerAddValue(long userId){
        Map<Integer, Integer> expMap = crossFiveHeroMatchData.getExpMap();
        CrossFiveHeroUserData userData = getUserData(userId);
        int expValue = 0;
        if(userData != null && userData.getCampId() != 0){
            if(expMap.containsKey(userData.getCampId())){
                expValue = expMap.get(userData.getCampId());
            }
        }
        int addPerValue = 0;
        if(expValue >= 0){
            addPerValue = config.getTechPerthAdd(expValue);
        }
        Map<Integer, CrossFiveHeroPatrons> pMap = new ConcurrentHashMap<>(userData.getPatronsMap());
        long allPatronsAb = 0;
        for(CrossFiveHeroPatrons patrons : pMap.values()){
            allPatronsAb = allPatronsAb + patrons.getAbility();
        }
        BigDecimal allAddAb = BigDecimal.valueOf(allPatronsAb);
        allAddAb = allAddAb.multiply(BigDecimal.valueOf(addPerValue)).divide(BigDecimal.valueOf(1000),0,BigDecimal.ROUND_UP);

        return allAddAb.longValue();
    }

    public void getPatrons(long userId, FiveHeroProto.FiveHeroGetPatronsReqMsg reqMsg) {
        //椒盐虾门客复活
        CrossFiveHeroUserData userData = getUserData(userId);
        if(userData == null || userData.getCampId() == 0){
            return;
        }
        int cityId = reqMsg.getCityId();
        CrossFiveHeroCity city = crossFiveHeroMatchData.getCityMap().get(cityId);
        FiveHeroProto.FiveHeroGetPatronsRespMsg.Builder respMsg = FiveHeroProto.FiveHeroGetPatronsRespMsg.newBuilder();
        if(reqMsg.getType() == 1){
            if(reqMsg.getPatronsId() != 0){
                CrossFiveHeroPatrons patrons = userData.getPatronsMap().get(reqMsg.getPatronsId());
                if(patrons != null){
                    FiveHeroProto.FiveHeroPatronsMsg.Builder patronsMsg = FiveHeroProto.FiveHeroPatronsMsg.newBuilder();
                    patronsMsg.setPatronsId(patrons.getId());
                    patronsMsg.setSkinId(patrons.getSkin());
                    patronsMsg.setMaxBlood(String.valueOf(getPatronsMaxBloodShield(patrons,city)));
                    patronsMsg.setBlood(String.valueOf(getPatronsBloodShield(patrons,city)));
                    patronsMsg.setReviveTimes(patrons.getReviveTimes());
                    patronsMsg.setReviveTime((int)(patrons.getLastReviveTime()/1000));
                    patronsMsg.setEventAdd(getEventAdd(patrons));
                    patronsMsg.setEventPerAdd(getEventPerAdd(patrons));
                    patronsMsg.setTokenId(0);//1到3地块不会被打
                    respMsg.addPatrons(patronsMsg);
                }
            }else{
                for(CrossFiveHeroPatrons patrons : userData.getPatronsMap().values()){
                    FiveHeroProto.FiveHeroPatronsMsg.Builder patronsMsg = FiveHeroProto.FiveHeroPatronsMsg.newBuilder();
                    patronsMsg.setPatronsId(patrons.getId());
                    patronsMsg.setSkinId(patrons.getSkin());
                    patronsMsg.setMaxBlood(String.valueOf(getPatronsMaxBloodShield(patrons,city)));
                    patronsMsg.setBlood(String.valueOf(getPatronsBloodShield(patrons,city)));
                    patronsMsg.setReviveTimes(patrons.getReviveTimes());
                    patronsMsg.setReviveTime((int)(patrons.getLastReviveTime()/1000));
                    patronsMsg.setEventAdd(getEventAdd(patrons));
                    patronsMsg.setEventPerAdd(getEventPerAdd(patrons));
                    patronsMsg.setTokenId(0);//1到3地块不会被打
                    respMsg.addPatrons(patronsMsg);
                }
            }

        }else if(reqMsg.getType() == 4){
            if(reqMsg.getPatronsId() != 0){
                CrossFiveHeroPatrons patrons = userData.getPatronsMap().get(reqMsg.getPatronsId());
                if(patrons != null){
                    FiveHeroProto.FiveHeroPatronsMsg.Builder patronsMsg = FiveHeroProto.FiveHeroPatronsMsg.newBuilder();
                    patronsMsg.setPatronsId(patrons.getId());
                    patronsMsg.setSkinId(patrons.getSkin());
                    patronsMsg.setMaxBlood(String.valueOf(getPatronsMaxBlood(patrons)));
                    patronsMsg.setBlood(String.valueOf(patrons.getType4nowBlood()));
                    patronsMsg.setReviveTimes(patrons.getType4reviveTimes());
                    patronsMsg.setReviveTime((int)(patrons.getType4lastReviveTime()/1000));
                    patronsMsg.setEventAdd(getEventAdd(patrons));
                    patronsMsg.setEventPerAdd(getEventPerAdd(patrons));
                    patronsMsg.setTokenId(patrons.getTokenId());
                    respMsg.addPatrons(patronsMsg);
                }
            }else {
                for(CrossFiveHeroPatrons patrons : userData.getPatronsMap().values()){
                    FiveHeroProto.FiveHeroPatronsMsg.Builder patronsMsg = FiveHeroProto.FiveHeroPatronsMsg.newBuilder();
                    patronsMsg.setPatronsId(patrons.getId());
                    patronsMsg.setSkinId(patrons.getSkin());
                    String maxBlood = String.valueOf(getPatronsMaxBlood(patrons));
                    patronsMsg.setMaxBlood(maxBlood);
                    //血量沒有血量的概念了
                    patronsMsg.setBlood(maxBlood);
                    patronsMsg.setReviveTimes(patrons.getType4reviveTimes());
                    patronsMsg.setReviveTime((int)(patrons.getType4lastReviveTime()/1000));
                    patronsMsg.setEventAdd(getEventAdd(patrons));
                    patronsMsg.setEventPerAdd(getEventPerAdd(patrons));
                    patronsMsg.setTokenId(patrons.getTokenId());
                    respMsg.addPatrons(patronsMsg);
                }
            }
        }
        respMsg.setUpdateTime((int)(userData.getUpdatePatronsTime()/1000));
        sendPacket(ClientProtocol.U_FIVEHERO_GET_PATRONS, respMsg, userId);
    }

    //校验是不是可以连接到自己的主城进行操作
    private boolean checkCanDo(int dealCityId,int campId){
        Map<Integer, List<Integer>> connectMap = FiveHeroMapLogic.getCityConnectMapConfig();
        Map<Integer, CrossFiveHeroCity> cityMap = crossFiveHeroMatchData.getCityMap();
        if(!cityMap.containsKey(dealCityId)){
            return false;
        }
        CrossFiveHeroCity city = cityMap.get(dealCityId);
        if(0 == campId){
            return false;
        }
        //不会操作自己的城池吧？
        if(city.getCampId() == campId){
            return false;
        }
        return checkLinkMainCity(dealCityId,campId,new ArrayList<>(),connectMap,cityMap);
    }

    //看看这个城池可以不可以连接到自己的主城畅通无阻
    private boolean checkLinkMainCity(int dealCityId,int campId,List<Integer> linkRing,Map<Integer, List<Integer>> connectMap,Map<Integer, CrossFiveHeroCity> cityMap){
        if(!connectMap.containsKey(dealCityId)){
            return false;
        }
        for(int linkCityId : connectMap.get(dealCityId)){
            if(!cityMap.containsKey(linkCityId)){
                continue;
            }
            //不能闭环，会死递归
            if(linkRing.contains(linkCityId)){
                continue;
            }
            if(cityMap.get(linkCityId).getCampId() == campId){
                FiveHeroCityConfig cityConfig = config.getCityConfig(linkCityId);
                if(cityConfig != null && cityConfig.getType() == 5){
                    return true;
                }
                linkRing.add(linkCityId);
                //如果可以连接就返回，不行就继续
                if(checkLinkMainCity(linkCityId,campId,linkRing,connectMap,cityMap)){
                    return true;
                }
            }
        }
        return false;
    }

    //恢复体力
    private void resumeHp(long userId){
        CrossFiveHeroUserData userData = getUserData(userId);
        long nowTime = System.currentTimeMillis();
        if(userData != null){
            long cutTime = nowTime - userData.getHpTime();
            long resumeTimes = cutTime / (config.getEnergyCdTime() * 1000);
            long newTime = userData.getHpTime() + resumeTimes * (config.getEnergyCdTime() * 1000);
            if(resumeTimes != 0){
                int oldHp = userData.getHp();
                if(userData.getHp() >= config.getEnergyMax()){

                }else{
                    if(userData.getHp() + resumeTimes * config.getEnergyCdNum() > config.getEnergyMax()){
                        userData.setHp(config.getEnergyMax());
                    }else{
                        userData.setHp(userData.getHp() + (int)resumeTimes * config.getEnergyCdNum());
                    }
                }
                userData.setHpTime(newTime);
                fhAc.addNeedUpdateUserData(userData);
                CrossAutoLogMgr.add(new LogFiveHeroUserHp(
                        groupId,
                        config.getActivityInfo().getActivityId(),
                        userId,
                        userData.getCampId(),
                        2,
                        userData.getHp() - oldHp,
                        userData.getHp()
                ));
            }

            if(resumeTimes > 0){
                syncUserDataMsg(userId);
            }
        }
    }

    //使用体力
    private void reduceHp(long userId,int reduceValue){
        CrossFiveHeroUserData userData = getUserData(userId);
        int oldHp = userData.getHp();
        userData.setHp(userData.getHp() - reduceValue);
        if(oldHp >= config.getEnergyMax() && userData.getHp() < config.getEnergyMax()){
            userData.setHpTime(System.currentTimeMillis());
        }
        fhAc.addNeedUpdateUserData(userData);
        syncUserDataMsg(userId);
        CrossAutoLogMgr.add(new LogFiveHeroUserHp(
                groupId,
                config.getActivityInfo().getActivityId(),
                userId,
                userData.getCampId(),
                1,
                -reduceValue,
                userData.getHp()
        ));
    }

    public void addHp(long userId,int addValue,int type){
        resumeHp(userId);
        CrossFiveHeroUserData userData = getUserData(userId);
        userData.setHp(userData.getHp() + addValue);
        fhAc.addNeedUpdateUserData(userData);
        syncUserDataMsg(userId);
        CrossAutoLogMgr.add(new LogFiveHeroUserHp(
                groupId,
                config.getActivityInfo().getActivityId(),
                userId,
                userData.getCampId(),
                type,
                addValue,
                userData.getHp()
        ));
    }

    //获取玩家对于要打的城市的pvp事件中的最吊的门客
    private CrossFiveHeroPatrons getUserTopCityPatrons(long userId,CrossFiveHeroCity city){
        CrossFiveHeroUserData userData = getUserData(userId);
        Map<Integer, CrossFiveHeroPatrons> patronsMap = userData.getPatronsMap();
        FiveHeroCityConfig cityConfig = config.getCityConfig(city.getCityId());
        LinkedList<CrossFiveHeroRank> sortList = new LinkedList<>();
        for(CrossFiveHeroPatrons patrons : patronsMap.values()){
            if(cityConfig.getType() == 4){
                if(patrons.getTokenId() != 0)continue;
            }else{
                if(patrons.getNowBlood() == 0)continue;
            }
            CrossFiveHeroRank rank = new CrossFiveHeroRank(patrons.getId() + "",getPatronsBloodShield(patrons,city),0L);
            sortList.add(rank);
        }
        if(sortList.size() > 0){
            sortList.sort(new CrossFiveHeroRankSort());
            int patronsId = Integer.valueOf(sortList.getFirst().getId());
            return patronsMap.get(patronsId);
        }

        return null;
    }

    public CrossFiveHeroPatrons getRandom6TopPatrons(long userId){
        CrossFiveHeroUserData userData = getUserData(userId);
        List<CrossFiveHeroPatrons> pList = getTopNumOccUserPatronsList(userData,config.getMakePvpTopPatronsNum());
        if(pList.size() > 0){
            int index = randomHelper.next(0,pList.size());
            return pList.get(index);
        }
        return null;
    }


    public void userReport(long userId, FiveHeroProto.FiveHeroReportUserReqMsg reqMsg) {
        FiveHeroProto.FiveHeroReportUserRespMsg.Builder respMsg = FiveHeroProto.FiveHeroReportUserRespMsg.newBuilder();
        respMsg.setRet(0);
        if(userReportMap.containsKey(reqMsg.getUserId())){
            List<CrossFiveHeroUserReport> reList = new ArrayList<>(userReportMap.get(reqMsg.getUserId()));
            for(CrossFiveHeroUserReport report : reList){
                FiveHeroProto.FiveHeroReportUserTempMsg.Builder reMsg = FiveHeroProto.FiveHeroReportUserTempMsg.newBuilder();
                reMsg.setCityId(report.getCityId());
                reMsg.setBattleCount(report.getBattleCount());
                reMsg.setRobReward(report.getRobReward());
                reMsg.setAttReward(report.getAttReward());
                reMsg.setTime((int)(report.getTime()/1000));
                reMsg.setNickName(report.getNickName());
                reMsg.setCampId(report.getCampId());
                respMsg.addData(reMsg);
            }
        }
        sendPacket(ClientProtocol.U_FIVEHERO_REPORT_USER, respMsg, userId);
    }

    public void cityReport(long userId, FiveHeroProto.FiveHeroReportCityReqMsg reqMsg) {
        FiveHeroProto.FiveHeroReportCityRespMsg.Builder respMsg = FiveHeroProto.FiveHeroReportCityRespMsg.newBuilder();
        respMsg.setRet(0);
        if(reqMsg.getType() == 1){
            for(CrossFiveHeroCityReport report : new ArrayList<>(cityReportList)){
                FiveHeroProto.FiveHeroReportCityTempMsg.Builder reMsg = FiveHeroProto.FiveHeroReportCityTempMsg.newBuilder();
                reMsg.setCampId(report.getCampId());
                reMsg.setBattleCount(report.getBattleCount());
                reMsg.setCityId(report.getCityId());
                reMsg.setDecoration(report.getDecoration());
                reMsg.setDefCampId(report.getDefCampId());
                reMsg.setIsRob(report.getIsRob() == 1);
                reMsg.setNickName(report.getNickName());
                reMsg.setTime((int)(report.getTime()/1000));
                reMsg.setUserId(report.getUserId());
                reMsg.setBeAttNickName(report.getBeAttTokenNickName());
                respMsg.addData(reMsg);
            }
        }else if(reqMsg.getType() == 2){
            for(CrossFiveHeroCityReport report : new ArrayList<>(cityReportLuoYangList)){
                FiveHeroProto.FiveHeroReportCityTempMsg.Builder reMsg = FiveHeroProto.FiveHeroReportCityTempMsg.newBuilder();
                reMsg.setCampId(report.getCampId());
                reMsg.setBattleCount(report.getBattleCount());
                reMsg.setCityId(report.getCityId());
                reMsg.setDecoration(report.getDecoration());
                reMsg.setDefCampId(report.getDefCampId());
                reMsg.setIsRob(report.getIsRob() == 1);
                reMsg.setNickName(report.getNickName());
                reMsg.setTime((int)(report.getTime()/1000));
                reMsg.setUserId(report.getUserId());
                reMsg.setBeAttNickName(report.getBeAttTokenNickName());
                respMsg.addData(reMsg);
            }
        }

        sendPacket(ClientProtocol.U_FIVEHERO_REPORT_CITY, respMsg, userId);
    }

    public void campInfo(long userId, FiveHeroProto.FiveHeroGetCampInfoReqMsg reqMsg) {
        FiveHeroProto.FiveHeroGetCampInfoRespMsg.Builder respMsg = FiveHeroProto.FiveHeroGetCampInfoRespMsg.newBuilder();
        respMsg.setRet(0);
        for(int campId = 1 ; campId <= config.getCampCount();campId++){
            FiveHeroProto.FiveHeroCampInfoMsg.Builder campMsg = FiveHeroProto.FiveHeroCampInfoMsg.newBuilder();
            campMsg.setCampId(campId);
            campMsg.setAddValue(getCampScoreSpeed(campId));
            campMsg.setScore((int)getCampScore(campId));
            campMsg.setTokenNum(getCampTokenList(campId).size());
            campMsg.setAddExpSpeed(getCampExpSpeed(campId));
            respMsg.addInfo(campMsg);
        }
        sendPacket(ClientProtocol.U_FIVEHERO_GET_CAMP_INFO, respMsg, userId);
    }

    public void luoYangResult(long userId) {
        FiveHeroProto.FiveHeroLuoYangResult.Builder respMsg = FiveHeroProto.FiveHeroLuoYangResult.newBuilder();
        CrossFiveHeroUserData userData = getUserData(userId);
        if(userData != null){
            Map<Integer, LogFiveHeroToken> tokenMap = userData.getLogTokenMap();
            for(LogFiveHeroToken tokenLog : tokenMap.values()){
                FiveHeroProto.FiveHeroLuoYangPatronsResult.Builder tokenMsg = FiveHeroProto.FiveHeroLuoYangPatronsResult.newBuilder();
                tokenMsg.setTokenId(tokenLog.getTokenId());
                tokenMsg.setTime((int)(tokenLog.getHasTime()/1000));
                tokenMsg.setPatronsId(tokenLog.getPatronsId());
                tokenMsg.setValue(tokenLog.getAddValue());
                tokenMsg.setBeRob(false);
                tokenMsg.setNickName("");
                respMsg.addResultList(tokenMsg);
            }
            userData.getLogTokenMap().clear();
        }
        sendPacket(ClientProtocol.U_FIVEHERO_GET_LUOYANG_RESULT, respMsg, userId);
    }

    public CrossFiveHeroChatLogic getChatLogic(){
        return chatLogic;
    }

    public void getChat(long userId, List<Integer> paramList, int param2) {
        List<WorldMessageProto.WorldMessageTempMsg> dataList = new ArrayList<>();
        if (paramList.isEmpty()) {
            return;
        }
        for (int range : paramList) {
            int id = 0;
            if (range == CrossFiveHeroChatLogic.RANGE_ALL) {
                id = config.getActivityInfo().getActivityId();
            } else if (range == CrossFiveHeroChatLogic.RANGE_CAMP) {
                id = getUserData(userId).getCampId();
            } else if (range == CrossFiveHeroChatLogic.RANGE_SYSTEM) {
                // 城池id
                id = config.getActivityId();
            }

            if (range <= 0 || id <= 0) {
                continue;
            }
            dataList.addAll(chatLogic.getChatMsg(range, id));
        }

        CrossActivityProto.CrossActivityChatListRespMsg.Builder respMsg = CrossActivityProto.CrossActivityChatListRespMsg.newBuilder();
        respMsg.setActivityId(config.getActivityInfo().getActivityId());
        UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(userId);
        if (userBaseInfo != null) {

            if (dataList.size() > 0) {
                dataList.sort(Comparator.comparingLong(WorldMessageProto.WorldMessageTempMsg::getSendTime));
                WorldMessageProto.WorldMessageListMsg.Builder worldMessageListMsg = WorldMessageProto.WorldMessageListMsg.newBuilder();
                worldMessageListMsg.addAllDataList(dataList);
                respMsg.setDataList(worldMessageListMsg);
            }
            YanQuMessage pbMsg = YanQuMessageUtils.buildMessage(Protocol.U_CROSS_ACTIVITY_CHAT_LIST, respMsg);
            MessageHelper.sendPacket(userBaseInfo.getServerId(), userId, pbMsg);
        }
    }

    //获取战功王，自己阵营声望最大的那个人
    private long getTopCampRankUser(int campId){
        long topUserId = 0;
        LinkedList<CrossFiveHeroRank> rankList = new LinkedList<>();
        for(CrossFiveHeroUserData userData : userDataMap.values()){
            if(userData.getCampId() == campId){
                CrossFiveHeroRank rank = new CrossFiveHeroRank(userData.getUserId()+ "",userData.getIntegral(),userData.getIntegralTime());
                rankList.add(rank);
            }
        }
        rankList.sort(new CrossFiveHeroRankSort());
        CrossFiveHeroRank rank = rankList.getFirst();
        if(rank != null){
            topUserId = Long.valueOf(rank.getId());
        }
        return topUserId;
    }

    //获取玩家的排名列表，要获取第一的变成城主
    public long getRankPopularity(int campId,int rankNum){
        LinkedList<CrossFiveHeroRank> rankList = new LinkedList<>();
        for(CrossFiveHeroUserData userData : userDataMap.values()){
            if(userData.getCampId() == campId){
                CrossFiveHeroRank rank = new CrossFiveHeroRank(userData.getUserId() + "",userData.getIntegral(),userData.getIntegralTime());
                rankList.add(rank);
            }
        }
        rankList.sort(new CrossFiveHeroRankSort());
        int rankIndex = 0;
        for(CrossFiveHeroRank rank : rankList){
            rankIndex++;
            if(rankIndex == rankNum){
                return Long.valueOf(rank.getId());
            }
        }
        return 0;
    }
    public long getTopPopularityUnionMasterId(int campId){
        LinkedList<CrossFiveHeroRank> rankList = new LinkedList<>();
        CrossFiveHeroRankListModel model = campUnionRankMap.get(campId);
        if (model != null) {
            rankList.addAll(model.getRankList());
        }
        rankList.sort(new CrossFiveHeroRankSort());
        CrossFiveHeroRank fRank = rankList.getFirst();
        if(fRank != null){
            CrossFiveHeroUnion union = unionMap.get(fRank.getId());
            for(CrossFiveHeroUnionMember member : union.getMemberMap().values()){
                if(member.getPosition() == eUnionPosition.Master.getValue())
                return member.getUserId();
            }
        }
        return 0;
    }

    //获取自己的排名
    public int getUserRankNum(long userId){
        String myId = String.valueOf(userId);
        LinkedList<CrossFiveHeroRank> rankList;
        rankList = userRank.getRankList();
        int maxRank = userMaxRankConfig;
        int myRank = -1;
        int rankNum = 0;
        for (CrossFiveHeroRank rank : rankList) {
            rankNum++;
            if (rankNum > maxRank) {
                break;
            }
            if (Objects.equals(rank.getId(), myId)) {
                myRank = rankNum;
                return myRank;
            }
        }
        return myRank;
    }

    //获取个人声望排行榜
    public void getUserRankList(long userId, FiveHeroProto.FiveHeroGetUserRankReqMsg reqMsg) {
        String unionUid = reqMsg.getUnionId();
        long myValue = getUserData(userId).getIntegral();
        String myId = String.valueOf(userId);
        LinkedList<CrossFiveHeroRank> rankList = new LinkedList<>();
        int maxRank = 100;

        LinkedList<CrossFiveHeroRank> gagaRankList = userRank.getRankList();
        if(!"".equals(unionUid)){
            for(CrossFiveHeroRank rank : gagaRankList){
                long rankUserId = Long.valueOf(rank.getId());
                CrossFiveHeroUserData userData = getUserData(rankUserId);
                if(userData != null && userData.getUnionUid().equals(unionUid)){
                    rankList.add(rank);
                }
            }
        }else{
            rankList = gagaRankList;
        }
        rankList.sort(new CrossFiveHeroRankSort());
        maxRank = userMaxRankConfig;

        FiveHeroProto.FiveHeroGetUserRankRespMsg.Builder builder = FiveHeroProto.FiveHeroGetUserRankRespMsg.newBuilder();
        builder.setRet(0);

        int myRank = -1;
        int rankNum = 0;
        for (CrossFiveHeroRank rank : rankList) {
            rankNum++;
            if (rankNum > maxRank) {
                break;
            }
            if (Objects.equals(rank.getId(), myId)) {
                myRank = rankNum;
            }
            builder.addRank(parseFiveHeroUserRankMsg(rank,rankNum));
        }

        builder.setMyRank(myRank);
        builder.setMyValue(myValue);
        sendPacket(ClientProtocol.U_FIVEHERO_GET_USER_RANK_LIST, builder, userId);
    }

    public CrossFiveHeroRankListModel getUserRank() {
        return userRank;
    }

    //阵营战功排行榜
    public LinkedList<CrossFiveHeroRank> getCampPopularityRank() {
        LinkedList<CrossFiveHeroRank> rankList = new LinkedList<>();
        for(int campId = 1; campId <= config.getCampCount();campId++){
            long value = getCampPopularity(campId);
            long time = getCampPopularityTime(campId);
            CrossFiveHeroRank rank = new CrossFiveHeroRank(campId + "",value,time);
            rankList.add(rank);
        }
        rankList.sort(new CrossFiveHeroRankSort());
        return rankList;
    }

    public FiveHeroProto.FiveHeroUserRankMsg.Builder parseFiveHeroUserRankMsg(CrossFiveHeroRank rank,int rankNum) {
        Long userId = Long.valueOf(rank.getId());
        UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(userId);
        if (userBaseInfo == null) {
            userBaseInfo = new UserBaseInfo();
        }
        int campId = getUserData(userId).getCampId();

        FiveHeroProto.FiveHeroUserRankMsg.Builder builder = FiveHeroProto.FiveHeroUserRankMsg.newBuilder();
        builder.setUserId(userId);
        builder.setPlayerBaseData(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
        builder.setValue(rank.getValue());
        builder.setCampId(campId);
        builder.setRank(rankNum);
        return builder;
    }

    public void campUnionRank(long userId, FiveHeroProto.FiveHeroGetCampUnionRankReqMsg reqMsg) {
        int campId = reqMsg.getCampId();
        CrossFiveHeroUserData userData = getUserData(userId);
        String unionUid = userData.getUnionUid();

        FiveHeroProto.FiveHeroGetCampUnionRankRespMsg.Builder builder = FiveHeroProto.FiveHeroGetCampUnionRankRespMsg.newBuilder();
        builder.setRet(0);
        List<CrossFiveHeroRank> rankList = new ArrayList<>();
        if (campId == 0) {
            // 获取全部商会
            for (CrossFiveHeroRankListModel model : campUnionRankMap.values()) {
                if (model != null) {
                    rankList.addAll(model.getRankList());
                }
            }
        } else {
            CrossFiveHeroRankListModel model = campUnionRankMap.get(campId);
            if (model != null) {
                rankList.addAll(model.getRankList());
            }
        }
        rankList.sort(new CrossFiveHeroRankSort());

        int rankShowLimit = unionMaxRankConfig;
        if (campId == 0) {
            rankShowLimit = unionMaxRankConfig * config.getCampCount();
        }
        // 获取商会排名
        int num = 0;
        for (CrossFiveHeroRank rank : rankList) {
            num++;
            if (num > rankShowLimit) {
                break;
            }
            builder.addRank(parseFiveHeroCampUnionRankMsg(rank));
        }

        // 获取商会阵营排名
        int myRank = -1;
        int myCampId = userData.getCampId();
        if (myCampId != 0) {
            CrossFiveHeroRankListModel model = campUnionRankMap.get(myCampId);
            if (model != null) {
                int cnt = 0;
                for (CrossFiveHeroRank rank : model.getRankList()) {
                    cnt++;
                    if (cnt > rankShowLimit) {
                        break;
                    }
                    if (Objects.equals(rank.getId(), unionUid)) {
                        myRank = cnt;
                    }
                }
            }
        }
        builder.setMyRank(myRank);

        long myValue = 0L;
        CrossFiveHeroUnion unionJoin = unionMap.get(unionUid);
        if (unionJoin != null) {
            for (CrossFiveHeroUnionMember member : unionJoin.getMemberMap().values()) {
                CrossFiveHeroUserData tmp = getUserData(member.getUserId());
                myValue += tmp.getIntegral();
            }
        }
        builder.setMyValue(myValue);

        sendPacket(ClientProtocol.U_FIVEHERO_GET_CAMP_UNION_RANK_LIST, builder, userId);
    }

    public LinkedList<CrossFiveHeroRank> campUnionRank() {
        LinkedList<CrossFiveHeroRank> rankList = new LinkedList<>();
        // 获取全部商会
        for (CrossFiveHeroRankListModel model : campUnionRankMap.values()) {
            if (model != null) {
                rankList.addAll(model.getRankList());
            }
        }
        rankList.sort(new CrossFiveHeroRankSort());

        return rankList;
    }


    public FiveHeroProto.FiveHeroCampUnionRankMsg.Builder parseFiveHeroCampUnionRankMsg(CrossFiveHeroRank rank) {
        String unionUid = rank.getId();
        CrossFiveHeroUnion crossFiveHeroUnionJoin = unionMap.get(unionUid);
        UnionBaseInfo unionBaseInfo = crossFiveHeroUnionJoin == null ? new UnionBaseInfo() : crossFiveHeroUnionJoin.getUnionBaseInfo();
        FiveHeroProto.FiveHeroCampUnionRankMsg.Builder builder = FiveHeroProto.FiveHeroCampUnionRankMsg.newBuilder();
        builder.setUnionUid(unionUid);
        builder.setValue(rank.getValue());
        builder.setUnionInfo(UnionBasePb.parseUnionBaseTempMsg(unionBaseInfo));
        builder.setCampId(crossFiveHeroUnionJoin == null ? 0 : crossFiveHeroUnionJoin.getCampId());
        return builder;
    }

    /**
     * 阵营积分榜单
     * @param getHistory 是不是加上所有结算的，还是只算当前城市的
     * @return
     */
    public LinkedList<CrossFiveHeroRank> getCampScoreRankList(boolean getHistory) {
        //每天晚上结算的，结算完了第二天继续再来一次结算，现在如果是最后一天了，占领完了再看就不算已经占领的坑了
        long nowTime = System.currentTimeMillis();
        Map<Integer, Long> campScoreMap = new ConcurrentHashMap<>();
        for(int campId = 1 ; campId <= config.getCampCount(); campId++){
            campScoreMap.put(campId,0L);
        }
        Map<Integer, Long> updateTimeMap = new ConcurrentHashMap<>();
        for (CrossFiveHeroCity city : crossFiveHeroMatchData.getCityMap().values()) {
            int campId = city.getCampId();
            int cityId = city.getCityId();

            if (campId == 0) {
                continue;
            }
            //比赛开始了才统计正在占领的，又改回去了
            /*if(nowTime > config.getTodayOutSideBeginTime() && nowTime < config.getTodayOutSideOverTime()){

            }*/
            // 统计积分
            int cityType = config.getCityConfigMap().get(cityId).getType();
            long addScore = config.getTypeConfig(cityType).getCampScore();
            long oldScore = campScoreMap.getOrDefault(campId, 0L);
            campScoreMap.put(campId, oldScore + addScore);
            // 存一下时间
            if (city.getOccupyTime() > updateTimeMap.getOrDefault(campId, 0L)) {
                updateTimeMap.put(campId, city.getOccupyTime());
            }
        }

        LinkedList<CrossFiveHeroRank> rankList = new LinkedList<>();
        Map<Integer, Long> wdnmdMap = crossFiveHeroMatchData.getScoreMap();
        for (Map.Entry<Integer, Long> entry : campScoreMap.entrySet()) {
            int campId = entry.getKey();
            String id = String.valueOf(campId);
            long value = entry.getValue();
            if(getHistory){
                value = value + wdnmdMap.getOrDefault(campId,0L);
            }
            //变成用积分和声望了，没时间什么事了
            CrossFiveHeroRank rank = new CrossFiveHeroRank(id, value, 0);
            rank.setAbility(getCampPopularity(campId));
            rankList.add(rank);
        }
        CrossFiveHeroRankListModel model = new CrossFiveHeroRankListModel();
        model.setRankList(rankList);

        return model.getRankList();
    }

    /*
    * 个人战令排行榜
    * */
    public LinkedList<CrossFiveHeroRank> getUserTokenRankList() {
        Map<Long,List<CrossFiveHeroToken>> userTokenMap = getUserTokenMap();

        LinkedList<CrossFiveHeroRank> rankList = new LinkedList<>();
        for(Long userId : userTokenMap.keySet()){
            CrossFiveHeroUserData userData = getUserData(userId);
            long time = 0;
            if(userData != null){
                time = userData.getTokenTime();
            }
            CrossFiveHeroRank rank = new CrossFiveHeroRank(userId + "", userTokenMap.get(userId).size(),time );
            rankList.add(rank);
        }

        CrossFiveHeroRankListModel model = new CrossFiveHeroRankListModel();
        model.setRankList(rankList);

        return model.getRankList();
    }

    /**
     * 阵营战令
     */
    public LinkedList<CrossFiveHeroRank> getCampTokenRankList() {
        Map<Long,List<CrossFiveHeroToken>> userTokenMap = getUserTokenMap();

        Map<Integer, Long> campTokenNumMap = new ConcurrentHashMap<>();
        Map<Integer, Long> updateTimeMap = new ConcurrentHashMap<>();
        for (long userId : userTokenMap.keySet()) {
            CrossFiveHeroUserData userData = getUserData(userId);
            if(userData == null){
                logger.debug("爆炸了啊啊啊啊啊");
                continue;
            }
            int campId = userData.getCampId();

            if (campId == 0) {
                continue;
            }
            List<CrossFiveHeroToken> tokenList = userTokenMap.get(userId);
            long tokenNum = tokenList.size();
            long allNum = campTokenNumMap.getOrDefault(campId,0L);
            allNum = allNum + tokenNum;
            campTokenNumMap.put(campId,allNum);
            // 存一下时间
            if (userData.getTokenTime() > updateTimeMap.getOrDefault(campId, 0L)) {
                updateTimeMap.put(campId, userData.getTokenTime());
            }
        }
        for(int campId = 1; campId <= config.getCampCount();campId++){
            if(!campTokenNumMap.containsKey(campId)){
                campTokenNumMap.put(campId,0L);
            }
        }

        LinkedList<CrossFiveHeroRank> rankList = new LinkedList<>();
        for (Map.Entry<Integer, Long> entry : campTokenNumMap.entrySet()) {
            int campId = entry.getKey();
            String id = String.valueOf(campId);
            CrossFiveHeroRank rank = new CrossFiveHeroRank(id, entry.getValue(), updateTimeMap.getOrDefault(entry.getKey(), System.currentTimeMillis()));
            rankList.add(rank);
        }

        CrossFiveHeroRankListModel model = new CrossFiveHeroRankListModel();
        model.setRankList(rankList);

        return model.getRankList();
    }

    public void campRank(long userId) {
        FiveHeroProto.FiveHeroGetCampRankRespMsg.Builder builder = FiveHeroProto.FiveHeroGetCampRankRespMsg.newBuilder();
        builder.setRet(0);

        LinkedList<CrossFiveHeroRank> rankList = getCampScoreRankList(true);
        rankList.sort(new CrossFiveHeroRankSort());
        int rankNum = 0;
        for (CrossFiveHeroRank rank : rankList) {
            rankNum++;
            builder.addRank(parseFiveHeroCampRankMsg(rank,rankNum));
        }

        sendPacket(ClientProtocol.U_FIVEHERO_GET_CAMP_RANK_LIST, builder, userId);
    }

    public FiveHeroProto.FiveHeroCampRankMsg.Builder parseFiveHeroCampRankMsg(CrossFiveHeroRank rank,int rankNum) {
        Integer campId = Integer.valueOf(rank.getId());

        FiveHeroProto.FiveHeroCampRankMsg.Builder builder = FiveHeroProto.FiveHeroCampRankMsg.newBuilder();
        builder.setCampId(campId);
        builder.setValue(rank.getValue());
        builder.setRank(rankNum);
        builder.setAddValue(getCampScoreSpeed(Integer.valueOf(rank.getId())));
        long userId = getMaxCampPUserId(campId);
        if(userId != 0){
            UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(userId);
            if (userBaseInfo == null) {
                userBaseInfo = new UserBaseInfo();
            }
            builder.setPlayerBaseData(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
        }
        return builder;
    }

    //声望最多的那个人的userId
    private long getMaxCampPUserId(int campId){
        long maxUserId = 0L;
        long maxP = -1L;
        for(CrossFiveHeroUserData userData : userDataMap.values()){
            if(userData.getCampId() == campId){
                if(userData.getIntegral() > maxP){
                    maxP = userData.getIntegral();
                    maxUserId = userData.getUserId();
                }
            }
        }
        return maxUserId;
    }

    //获取玩家的排名
    public int getUserTokenRankNum(long userId){
        LinkedList<CrossFiveHeroRank> rankList = getUserTokenRankList();
        rankList.sort(new CrossFiveHeroRankSort());
        int rankNum = 0;
        for (CrossFiveHeroRank rank : rankList) {
            rankNum++;
            if(Long.valueOf(rank.getId()) == userId){
                return rankNum;
            }
        }
        return -1;
    }
    //获取前三玩家
    public LinkedList<CrossFiveHeroRank> getUserTokenRankTop3(long userId){
        LinkedList<CrossFiveHeroRank> retList = new LinkedList<>();
        LinkedList<CrossFiveHeroRank> rankList = getUserTokenRankList();
        rankList.sort(new CrossFiveHeroRankSort());
        int rankNum = 0;
        for (CrossFiveHeroRank rank : rankList) {
            rankNum++;
            if(rankNum <= 3){
                retList.add(rank);
            }else{
                break;
            }
        }
        return retList;
    }

    public void userTokenRank(long userId) {
        FiveHeroProto.FiveHeroGetUserTokenRankRespMsg.Builder builder = FiveHeroProto.FiveHeroGetUserTokenRankRespMsg.newBuilder();
        builder.setRet(0);
        builder.setMyValue(-1);
        builder.setMyRank(-1);
        LinkedList<CrossFiveHeroRank> rankList = getUserTokenRankList();
        rankList.sort(new CrossFiveHeroRankSort());
        int rankNum = 0;
        for (CrossFiveHeroRank rank : rankList) {
            rankNum++;
            builder.addRank(parseFiveHeroUserRankMsg(rank,rankNum));
            if(Long.valueOf(rank.getId()) == userId){
                builder.setMyValue(rank.getValue());
                builder.setMyRank(rankNum);
            }
        }

        sendPacket(ClientProtocol.U_FIVEHERO_GET_USER_TOKEN_RANK_LIST, builder, userId);
    }

    //阵营战令排行榜
    public void campTokenRank(long userId) {
        FiveHeroProto.FiveHeroGetCampTokenRankRespMsg.Builder builder = FiveHeroProto.FiveHeroGetCampTokenRankRespMsg.newBuilder();
        builder.setRet(0);

        LinkedList<CrossFiveHeroRank> rankList = getCampTokenRankList();
        rankList.sort(new CrossFiveHeroRankSort());
        int rankNum = 0;
        for (CrossFiveHeroRank rank : rankList) {
            rankNum++;
            builder.addRank(parseFiveHeroCampRankMsg(rank,rankNum));
        }

        sendPacket(ClientProtocol.U_FIVEHERO_GET_CAMP_TOKEN_RANK_LIST, builder, userId);
    }

    public void selfToken(long userId) {
        CrossFiveHeroUserData userData = getUserData(userId);
        CrossFiveHeroCity city = getLuoYangCity();
        List<CrossFiveHeroToken> tokenList = getUserTokenList(userId);
        FiveHeroProto.FiveHeroGetSelfTokenRespMsg.Builder respMsg = FiveHeroProto.FiveHeroGetSelfTokenRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setTokenNum(tokenList.size());
        for(CrossFiveHeroToken token : new ArrayList<>(city.getDefTokenMap().values())){
            FiveHeroProto.FiveHeroPatronsTokenMsg.Builder tokenMsg = FiveHeroProto.FiveHeroPatronsTokenMsg.newBuilder();
            tokenMsg.setTokenId(token.getTokenId());
            tokenMsg.setAll(0);
            tokenMsg.setAll(token.getValue());
            tokenMsg.setPatronsId(token.getDefPatrons().getId());
            tokenMsg.setUserId(token.getUserId());
            tokenMsg.setCampId(0);
            CrossFiveHeroUserData tokenUserData = getUserData(token.getUserId());
            if(tokenUserData != null){
                tokenMsg.setCampId(tokenUserData.getCampId());
            }
            tokenMsg.setMaxBlood(token.getDefPatrons().getMaxBlood());
            tokenMsg.setNowBlood(token.getDefPatrons().getNowBlood());
            tokenMsg.setNickName("");
            if(token.getUserId() != 0){
                UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(token.getUserId());
                if(userBaseInfo != null){
                    tokenMsg.setNickName(userBaseInfo.getNickName());
                }
            }else{
                FiveHeroOrderConfig orderConfig = config.getOrderConfig(token.getTokenId());
                tokenMsg.setNickName(ServerLanguageMgr.getContent(orderConfig.getTeamName(), userData.getLanguage()));
            }

            respMsg.addInfo(tokenMsg);
        }
        for(CrossFiveHeroPatrons patrons : userData.getPatronsMap().values()){
            if(patrons.getTokenId() != 0){
                boolean isToken = false;
                for(CrossFiveHeroToken token : tokenList){
                    if(token.getDefPatrons().getId() == patrons.getId()){
                        isToken = true;
                        break;
                    }
                }
                if(isToken == false){
                    logger.info("玩家{}出现门客{}，在战令{}，却不在的",userId,patrons.getId(),patrons.getTokenId());
                    patrons.setTokenId(0);
                }
            }
        }
        sendPacket(ClientProtocol.U_FIVEHERO_SELF_TOKEN, respMsg, userId);
    }

    public void sendChat(long userId, CrossActivityProto.CrossActivityChatReqMsg.Builder reqMsg) {
        int range = 0;
        int id = 0;
        if (eMessageType.FiveHeroPublicChat.getValue() == reqMsg.getMsg().getType()) {
            range = CrossFiveHeroChatLogic.RANGE_ALL;
            id = config.getActivityInfo().getActivityId();
            // 公屏聊天加上阵营
            WorldMessageProto.WorldMessageTempMsg.Builder message = reqMsg.getMsg().toBuilder();
            message.setExtraParams(String.valueOf(getUserData(userId).getCampId()));
            reqMsg.setMsg(message);
        } else if (eMessageType.FiveHeroCampChat.getValue() == reqMsg.getMsg().getType()) {
            range = CrossFiveHeroChatLogic.RANGE_CAMP;
            id = getUserData(userId).getCampId();
        }

        if (range <= 0 || id <= 0) {
            return;
        }

        chatLogic.chat(range, id, 1, reqMsg.getMsg(),groupId);
    }

    //排行榜变化
    public void changeRank(long userId) {
        CrossFiveHeroUserData userData = getUserData(userId);
        CrossFiveHeroRank rank = new CrossFiveHeroRank(String.valueOf(userId), userData.getIntegral(), System.currentTimeMillis());
        userRank.rankChange(rank);

        // 阵营内个人榜
        campUserRankMap.putIfAbsent(userData.getCampId(), new CrossFiveHeroRankListModel());
        campUserRankMap.get(userData.getCampId()).rankChange(rank);

        // 阵营内商会榜
        CrossFiveHeroUnion join = unionMap.get(userData.getUnionUid());
        if (join != null) {
            long unionValue = 0;
            for (long memberId : join.getMemberMap().keySet()) {
                CrossFiveHeroUserData memberData = getUserData(memberId);
                unionValue += memberData.getIntegral();
            }

            CrossFiveHeroRank unionRank = new CrossFiveHeroRank(join.getUnionUid(), unionValue, System.currentTimeMillis());
            if (join.getTotalAbility() == 0L) {
                join.reCalcAbility();
            }
            unionRank.setAbility(join.getTotalAbility());

            campUnionRankMap.putIfAbsent(userData.getCampId(), new CrossFiveHeroRankListModel());
            campUnionRankMap.get(userData.getCampId()).rankChange(unionRank);
        }
    }

    public void horseLamp(long userId, FiveHeroProto.FiveHeroHorseLampReqMsg reqMsg) {
        FiveHeroProto.FiveHeroHorseLampSyncMsg.Builder respMsg = FiveHeroProto.FiveHeroHorseLampSyncMsg.newBuilder();
        respMsg.setIsSync(false);
        FiveHeroProto.FiveHeroHorseLampMsg.Builder lpMsg = FiveHeroProto.FiveHeroHorseLampMsg.newBuilder();
        lpMsg.setType(1);
    }


    //大到小
    static class PatronsQualificationSort implements Comparator<CrossFiveHeroPatrons> {
        @Override
        public int compare(CrossFiveHeroPatrons o1, CrossFiveHeroPatrons o2) {
            if (o1.getAbility() == o2.getAbility()) {
                return 0;
            }
            if (o1.getAbility() > o2.getAbility()) {
                return -1;
            }
            return 1;
        }
    }

    static class BattlePatronsBloodSort implements Comparator<CrossFiveHeroBattlePatrons> {
        @Override
        public int compare(CrossFiveHeroBattlePatrons o1, CrossFiveHeroBattlePatrons o2) {
            if (o1.getNowBlood() == o2.getNowBlood()) {
                return 0;
            }
            if (o1.getNowBlood() > o2.getNowBlood()) {
                return -1;
            }
            return 1;
        }
    }

    //获取对应职业全部门客能力值和
    private BigInteger getOccPatronsAbAll(long userId , CrossFiveHeroCity city){
        FiveHeroCityConfig cityConfig = config.getCityConfig(city.getCityId());
        CrossFiveHeroUserData userData = getUserData(userId);
        Map<Integer, CrossFiveHeroPatrons> patronsMap = new ConcurrentHashMap<>(userData.getPatronsMap());
        List<CrossFiveHeroPatrons> yesList = new ArrayList<>();
        for(CrossFiveHeroPatrons patrons : patronsMap.values()){
            PatronsInfo patronsInfo = PatronsMgr.getPatronsInfo(patrons.getId());
            if(patronsInfo.getOccupation() == cityConfig.getJobBuffEffectList().get(0)){
                yesList.add(patrons);
            }
        }
        BigInteger allValue = BigInteger.ZERO;
        for(CrossFiveHeroPatrons patrons : yesList){
            allValue = allValue.add(BigInteger.valueOf(patrons.getAbility()));
        }
        return allValue;
    }

    //每日结束了不能打了
    private int checkPublicBattle(int cityId){
        long nowTime = System.currentTimeMillis();
        if( config.getLuoYangId() == cityId){
            if(isTodayTokenScoreOver()){
                return GameErrorCode.E_FIVE_HERO_NOT_INT_LUOYANG_BATTLE_TIME;
            }
            long todayBeginInSideTime = config.getTodayInSideBeginTime();
            long todayOverInSideTime = config.getTodayInSideOverTime();
            if(nowTime < todayBeginInSideTime){
                return GameErrorCode.E_FIVE_HERO_NOT_INT_LUOYANG_BATTLE_TIME;
            }
            if(nowTime > todayOverInSideTime){
                return GameErrorCode.E_FIVE_HERO_NOT_INT_LUOYANG_BATTLE_TIME;
            }
        }else{
            long todayBeginOutSideTime = config.getTodayOutSideBeginTime();
            long todayOverOutSideTime = config.getTodayOutSideOverTime();
            if(nowTime < todayBeginOutSideTime){
                return GameErrorCode.E_FIVE_HERO_NOT_INT_CITY_BATTLE_TIME;
            }
            if(nowTime > todayOverOutSideTime){
                return GameErrorCode.E_FIVE_HERO_NOT_INT_CITY_BATTLE_TIME;
            }
        }
        return 0;
    }

    public void logGift(long userId, FiveHeroProto.CrossFiveHeroGiftLogMsg reqMsg) {
        CrossFiveHeroUserData userData = getUserData(userId);
        CrossAutoLogMgr.add(new LogFiveHeroRmbGift(
                groupId,
                config.getActivityInfo().getActivityId(),
                userId,
                userData.getCampId(),
                reqMsg.getCityId(),
                reqMsg.getMallId()
        ));
    }


    private List<FiveHeroProto.FiveHeroBattleBanditRecordTempMsg> getAttBanditList(CrossFiveHeroBandit bandit){
        List<FiveHeroProto.FiveHeroBattleBanditRecordTempMsg> resList = new ArrayList<>();
        Map<Long, Long> aaMap = new ConcurrentHashMap<>(bandit.getUserAttackMap());
        LinkedList<CrossFiveHeroRank> rankList = new LinkedList<>();
        for(long attUserId : aaMap.keySet()){
            rankList.add(new CrossFiveHeroRank(attUserId + "",aaMap.get(attUserId),0L));
        }
        rankList.sort(new CrossFiveHeroRankSort());
        int rankNum = 0;
        for(CrossFiveHeroRank rank : rankList){
            rankNum++;
            FiveHeroProto.FiveHeroBattleBanditRecordTempMsg.Builder rankMsg = FiveHeroProto.FiveHeroBattleBanditRecordTempMsg.newBuilder();
            rankMsg.setRank(rankNum);
            long userId = Long.valueOf(rank.getId());
            UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(userId);
            if(userBaseInfo != null){
                rankMsg.setNickName(userBaseInfo.getNickName());
            }else{
                rankMsg.setNickName("");
            }
            rankMsg.setValue(rank.getValue());
            resList.add(rankMsg.build());
        }
        return resList;
    }

    public void searchCity(long userId, FiveHeroProto.FiveHeroCitySearchReqMsg reqMsg) {
        FiveHeroProto.FiveHeroCitySearchRespMsg.Builder respMsg = FiveHeroProto.FiveHeroCitySearchRespMsg.newBuilder();
        respMsg.setRet(0);
        int cityId = reqMsg.getCityId();
        synchronized (getCityPvpLock(cityId)){
            int ret = checkPublicBattle(cityId);
            if(ret != 0){
                respMsg.setRet(ret);
                sendPacket(ClientProtocol.U_FIVEHERO_CITY_SEARCH, respMsg, userId);
                return;
            }
            Map<Integer, CrossFiveHeroCity> cityMap = crossFiveHeroMatchData.getCityMap();
            if(!cityMap.containsKey(cityId)){
                respMsg.setRet(GameErrorCode.E_FIVE_HERO_PARAMS_ERR);
                sendPacket(ClientProtocol.U_FIVEHERO_CITY_SEARCH, respMsg, userId);
                return;
            }
            //判断连接和判断是不是被其他占领
            CrossFiveHeroCity city = cityMap.get(cityId);
            CrossFiveHeroUserData userData = getUserData(userId);
            if(userData == null || userData.getCampId() == 0){
                respMsg.setRet(GameErrorCode.E_FIVE_HERO_PARAMS_ERR);
                sendPacket(ClientProtocol.U_FIVEHERO_CITY_SEARCH, respMsg, userId);
                return;
            }
            if(!cityBattleUserIdMap.containsKey(cityId) || !cityBattleUserIdMap.get(cityId).containsKey(userId) || cityBattleUserIdMap.get(cityId).get(userId) != city.getCampId() || userData.getCampId() == city.getCampId()){
                respMsg.setRet(GameErrorCode.E_FIVE_HERO_STATUS_CHANGE);
                sendPacket(ClientProtocol.U_FIVEHERO_CITY_SEARCH, respMsg, userId);
                return;
            }
            if(!checkCanDo(cityId,userData.getCampId())){
                int luoyangId = config.getLuoYangId();
                //经过讨论后得出的方案是道路被阻断了，只有洛阳城会提示阻断其他地方不论是探索还是攻击，都是状态不对
                if(city.getCityId() == luoyangId){
                    respMsg.setRet(GameErrorCode.E_FIVE_HERO_LUOYANG_NOT_ROUTE);
                }else{
                    respMsg.setRet(GameErrorCode.E_FIVE_HERO_LUOYANG_NOT_ROUTE);
                }
                sendPacket(ClientProtocol.U_FIVEHERO_CITY_SEARCH, respMsg, userId);
                return;
            }
            FiveHeroCityConfig cityConfig = config.getCityConfig(cityId);
            FiveHeroTypeConfig typeConfig = config.getTypeConfig(cityConfig.getType());
            resumeHp(userId);
            if(typeConfig.getType() != 4){
                if(userData.getHp() < typeConfig.getEnergyCost()){
                    respMsg.setRet(GameErrorCode.E_FIVE_HERO_HP_NOT_ENOUGH);
                    sendPacket(ClientProtocol.U_FIVEHERO_CITY_SEARCH, respMsg, userId);
                    return;
                }
                reduceHp(userId,typeConfig.getEnergyCost());
                FiveHeroProto.CrossFiveHeroCostMsg.Builder builder = FiveHeroProto.CrossFiveHeroCostMsg.newBuilder();
                builder.setActivityId(getActivityInfo().getActivityId());
                builder.setCostCount(typeConfig.getEnergyCost());
                MessageHelper.sendPacket(userData.getServerId(), userData.getUserId(), YanQuMessageUtils.buildMessage(GameProtocol.S_FIVEHERO_COST_STAMINE, builder));
            }
            int eventId = config.randomEvent(cityId);
            userData.setEventId(eventId);
            userData.setEventCityId(city.getCityId());
            userData.setEventCampId(city.getCampId());
            FiveHeroEventConfig eventConfig = config.getEventConfig(eventId);
            respMsg.setEventId(eventId);
            if(eventConfig.getType() == 1){//pvp事件
                CrossFiveHeroPatrons patrons = getUserTopCityPatrons(userId,city);
                if(patrons != null){
                    respMsg.setPatronId(patrons.getId());
                    respMsg.setMaxBlood(String.valueOf(getPatronsMaxBloodShield(patrons,city)));
                    respMsg.setNBlood(String.valueOf(getPatronsBloodShield(patrons,city)));
                }else{
                    respMsg.setPatronId(0);
                    respMsg.setMaxBlood("0");
                    respMsg.setNBlood("0");
                }
                if(city.getOccUserId() != 0){
                    UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(city.getOccUserId());
                    if(userBaseInfo != null){
                        respMsg.setUser(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
                    }
                }
            }else if(eventConfig.getType() == eFiveHeroEventType.Bandit.getValue()){//山贼
                List<Integer> parameterList = eventConfig.getParameterList();
                int banditId = parameterList.get(0);
                Map<Integer, CrossFiveHeroBandit> banditMap = city.getBanditMap();
                if(banditMap.containsKey(banditId)){
                    //记录一下是哪一只山贼，死了就不大了退体力，。。。。。。。。。。。。。。
                    CrossFiveHeroBandit bandit = banditMap.get(banditId);
                    userData.setBanditNo(bandit.getDieCount());
                    respMsg.setAllBlood(bandit.getMaxBlood().toString());
                    respMsg.setNowBlood(bandit.getBlood().toString());
                    respMsg.addAllRecords(getAttBanditList(bandit));
                }else{
                    //没了就再生一下
                    logger.debug("山贼没了啊{}",banditId);
                    respMsg.setRet(GameErrorCode.E_FIVE_HERO_SYSTEM_ERROR);
                    sendPacket(ClientProtocol.U_FIVEHERO_CITY_SEARCH, respMsg, userId);
                    return;
                }
                CrossFiveHeroPatrons patrons = getUserTopCityPatrons(userId,city);
                if(patrons != null){
                    respMsg.setPatronId(patrons.getId());
                    respMsg.setMaxBlood(String.valueOf(getPatronsMaxBloodShield(patrons,city)));
                    respMsg.setNBlood(String.valueOf(getPatronsBloodShield(patrons,city)));
                }else{
                    respMsg.setPatronId(0);
                    respMsg.setMaxBlood("0");
                    respMsg.setNBlood("0");
                }
            }else if(eventConfig.getType() == eFiveHeroEventType.SoldierGet.getValue()){//士兵投奔
                CrossFiveHeroPatrons patrons = getRandom6TopPatrons(userId);
                if(patrons == null){
                    respMsg.setRet(GameErrorCode.E_FIVE_HERO_SYSTEM_ERROR);
                    sendPacket(ClientProtocol.U_FIVEHERO_CITY_SEARCH, respMsg, userId);
                    return;
                }
                List<Integer> pList = eventConfig.getParameterList();
                //这里直接加到血量上去
                long oldValue = getPatronsMaxBlood(patrons);
                long addToBloodValue = 0;
                if(pList.size() > 1 && pList.get(1) > 0){
                    int addValue = pList.get(1);
                    Map<Integer, Long> addMap = patrons.getAddAbilityMap();
                    addMap.put(addMap.size() + 1,(long)addValue);
                    patrons.setAddAbilityMap(addMap);
                    addToBloodValue = addToBloodValue + addValue;
                }
                if(pList.size() > 2 && pList.get(2) > 0){
                    int addValue = pList.get(2);
                    Map<Integer, Long> addMap = patrons.getAddPercentageAbilityMap();
                    addMap.put(addMap.size() + 1,(long)addValue);
                    patrons.setAddPercentageAbilityMap(addMap);
                    BigDecimal ab = BigDecimal.valueOf(patrons.getAbility());
                    ab = ab.multiply(BigDecimal.valueOf(addValue)).divide(BigDecimal.valueOf(1000),0,BigDecimal.ROUND_UP);
                    addToBloodValue = addToBloodValue + ab.longValue();
                }
                long newValue = getPatronsMaxBlood(patrons);
                /*CrossFiveHeroLog.addLogFiveHeroPatronsUpdate(new LogFiveHeroPatronsUpdate(
                        groupId,
                        config.getActivityInfo().getActivityId(),
                        userId,
                        userData.getCampId(),
                        patrons.getId(),
                        1,
                        newValue - oldValue,
                        oldValue,
                        newValue
                ));*/
                if(patrons.getNowBlood() != 0){
                    patrons.setNowBlood(patrons.getNowBlood() + addToBloodValue);
                }
                if(patrons.getType4nowBlood() != 0){
                    patrons.setType4nowBlood(patrons.getType4nowBlood() + addToBloodValue);
                }
                fhAc.addNeedUpdatePatronsData(patrons);
                FiveHeroProto.FiveHeroEventPatronsAddMsg.Builder addPMsg = FiveHeroProto.FiveHeroEventPatronsAddMsg.newBuilder();
                addPMsg.setPatronsId(patrons.getId());
                addPMsg.setBaseAbility(patrons.getAbility());
                addPMsg.setAbility(getPatronsMaxBlood(patrons));
                FiveHeroProto.FiveHeroCitySearchEventResultMsg.Builder otherPMsg = FiveHeroProto.FiveHeroCitySearchEventResultMsg.newBuilder();
                otherPMsg.setReward(PropertyHelper.parsePropertyToString(PropertyHelper.parseNewStringToProperty(eventConfig.getRewards())));
                otherPMsg.setPatronsAdd(addPMsg);
                respMsg.setOtherResult(otherPMsg);
            }else if(eventConfig.getType() == eFiveHeroEventType.Scroll.getValue()){//残卷抽取
                FiveHeroProto.FiveHeroCitySearchEventResultMsg.Builder otherPMsg = FiveHeroProto.FiveHeroCitySearchEventResultMsg.newBuilder();
                otherPMsg.setReward(PropertyHelper.parsePropertyToString(PropertyHelper.parseNewStringToProperty(eventConfig.getRewards())));
                respMsg.setOtherResult(otherPMsg);
            }else if(eventConfig.getType() == eFiveHeroEventType.Baggage.getValue()){//辎重
                FiveHeroProto.FiveHeroCitySearchEventResultMsg.Builder otherPMsg = FiveHeroProto.FiveHeroCitySearchEventResultMsg.newBuilder();
                otherPMsg.setReward(PropertyHelper.parsePropertyToString(PropertyHelper.parseNewStringToProperty(eventConfig.getRewards())));
                respMsg.setOtherResult(otherPMsg);
            }else if(eventConfig.getType() == eFiveHeroEventType.Businessman.getValue()){//珍宝商人
                FiveHeroProto.FiveHeroCitySearchEventResultMsg.Builder otherPMsg = FiveHeroProto.FiveHeroCitySearchEventResultMsg.newBuilder();
                String reward = PropertyHelper.parsePropertyToString(PropertyHelper.parseNewStringToProperty(eventConfig.getRewards()));
                otherPMsg.setReward(reward);
                respMsg.setOtherResult(otherPMsg);
                FiveHeroProto.FiveHeroNotifyGameServerShop.Builder builder = FiveHeroProto.FiveHeroNotifyGameServerShop.newBuilder();
                builder.setStat(0);
                FiveHeroProto.CrossFiveHeroGiftLogMsg.Builder logMsg = FiveHeroProto.CrossFiveHeroGiftLogMsg.newBuilder();
                logMsg.setActivityId(config.getActivityId());
                logMsg.setUserId(userId);
                logMsg.setCityId(reqMsg.getCityId());
                builder.setLog(logMsg);
                MessageHelper.sendPacket(userData.getServerId(), userData.getUserId(), YanQuMessageUtils.buildMessage(GameProtocol.S_FIVEHERO_NOTIFY_SHOP_FROM_CROSS, builder));
            }else if(eventConfig.getType() == eFiveHeroEventType.LuoYang.getValue()){//洛阳事件
                long itemNum = reqMsg.getItemNum();
                int cost = config.getAttLuoYangCost(userData.getLuoYangAttTimes() + 1);
                // 元宝负数的这边过不去免费次数，    消耗为0不处理
                if (cost > 0 && cost > itemNum) {
                    respMsg.setRet(GameErrorCode.E_BAG_ITEM_NO_ENOUGH);
                    sendPacket(ClientProtocol.U_FIVEHERO_CITY_SEARCH, respMsg, userId);
                    return;
                }
//          List<CrossFiveHeroToken> tokenList = getOtherCampUserTokenList(city,userData.getCampId());
                List<CrossFiveHeroToken> tokenList = getOtherCampTokenList(city,userData.getCampId());
                if(tokenList.size() == 0){
                    respMsg.setRet(GameErrorCode.E_FIVE_HERO_LUOYANG_ALL_ROB);
                    sendPacket(ClientProtocol.U_FIVEHERO_CITY_SEARCH, respMsg, userId);
                    return;
                }
                CrossFiveHeroPatrons p = getUserTopCityPatrons(userId,city);
                if(p == null){
                    respMsg.setRet(GameErrorCode.E_FIVE_HERO_LUOYANG_NO_PATRONS);
                    sendPacket(ClientProtocol.U_FIVEHERO_CITY_SEARCH, respMsg, userId);
                    return;
                }
                int randomIndex = randomHelper.next(0,tokenList.size());
                CrossFiveHeroToken token = tokenList.get(randomIndex);
                userData.setUpdateTime(token.getUserId());
                FiveHeroProto.FiveHeroCitySearchLuoYangResultMsg.Builder luoyangMsg = FiveHeroProto.FiveHeroCitySearchLuoYangResultMsg.newBuilder();
                FiveHeroOrderConfig orderConfig = config.getOrderConfig(token.getTokenId());
                String nickName = orderConfig.getTeamName();
                nickName = ServerLanguageMgr.getContent(nickName, userData.getLanguage());
                if(token.getUserId() != 0){
                    UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(token.getUserId());
                    if(userBaseInfo != null){
                        nickName = userBaseInfo.getNickName();
                    }
                }
                userData.setEventTokenId(token.getTokenId());
                luoyangMsg.setNickName(nickName);
                luoyangMsg.setCampId(token.getCampId());
                luoyangMsg.setTokenId(token.getTokenId());
                luoyangMsg.setMaxBlood(String.valueOf(token.getDefPatrons().getMaxBlood()));
                luoyangMsg.setNBlood(String.valueOf(token.getDefPatrons().getNowBlood()));
                luoyangMsg.setPatronId(token.getDefPatrons().getId());
                luoyangMsg.setSkinId(token.getDefPatrons().getSkin());
                luoyangMsg.setCost(cost);
                respMsg.setLuoyangResult(luoyangMsg);
            }
            fhAc.addNeedUpdateUserData(userData);
            MessageHelper.sendPacket(userData.getServerId(), userData.getUserId(), YanQuMessageUtils.buildMessage(GameProtocol.S_FIVEHERO_NOTIFY_EVENT, respMsg));
        }
    }

    //占领成功后
    private void robSuccess(CrossFiveHeroCity city,int campId,long userId){
        city.setOccUserId(userId);
        city.setCampId(campId);
        FiveHeroCityConfig cityConfig = config.getCityConfig(city.getCityId());
        Map<Integer,CrossFiveHeroBattlePatrons> rpMap = getRandomPatronsPvpV2(cityConfig,getUserData(userId));
        city.setDefPatronsMap(rpMap);
        FiveHeroTypeConfig typeConfig = config.getTypeConfig(cityConfig.getType());
        //todo-xx 血量
        city.getKillCountMap().put(1L,typeConfig.getBloodList().get(0));
        city.setDiePatronsList(new LinkedList());
        //占领了从现在开始算经验加成
        city.setExpAddTime(System.currentTimeMillis());
        city.setOccupyTime(System.currentTimeMillis());
        addNeedUpdateCityData(city);
        if(cityBattleUserIdMap.containsKey(city.getCityId())){
            cityBattleUserIdMap.get(city.getCityId()).clear();
        }
        addCityChange(city.getCityId());
    }

    //从大到小
    static class UserReportSort implements Comparator<CrossFiveHeroUserReport> {
        @Override
        public int compare(CrossFiveHeroUserReport o1, CrossFiveHeroUserReport o2) {
            if (o1.getTime() == o2.getTime()) {
                return 0;
            }
            if (o1.getTime() > o2.getTime()) {
                return -1;
            }
            return 1;
        }
    }

    //从大到小
    static class CityReportSort implements Comparator<CrossFiveHeroCityReport> {
        @Override
        public int compare(CrossFiveHeroCityReport o1, CrossFiveHeroCityReport o2) {
            if (o1.getTime() == o2.getTime()) {
                return 0;
            }
            if (o1.getTime() > o2.getTime()) {
                return -1;
            }
            return 1;
        }
    }

    //生成个人战报
    private CrossFiveHeroUserReport makeUserReport(long userId,int cityId,int campId,int killCount,String attReward,String robReward,String nickName){
        CrossFiveHeroUserReport report = new CrossFiveHeroUserReport();
        report.setUserId(userId);
        report.setActivityId(config.getActivityId());
        report.setGroupId(groupId);
        report.setBattleCount(killCount);
        report.setAttReward(attReward);
        report.setCampId(campId);
        report.setCityId(cityId);
        report.setNickName(nickName);
        report.setRobReward(robReward);
        report.setTime(System.currentTimeMillis());
        if(!userReportMap.containsKey(userId)){
            userReportMap.put(userId,new ArrayList<>());
        }
        if(userReportMap.get(userId).size() >= config.getCityReportNum()){
            userReportMap.get(userId).sort(new UserReportSort());
            userReportMap.get(userId).remove(userReportMap.get(userId).size() - 1);
        }
        userReportMap.get(userId).add(report);
        addRedDot(userId, eFiveHeroRedDotType.Type1_UserReport);
        addNeedInsertUserReportData(report);
        return report;
    }

    //生成城池战报
    private CrossFiveHeroCityReport makeCityReport(long userId,int cityId,int campId,int killCount,int isRob,String nickName){
        int luoyangId = config.getLuoYangId();
        CrossFiveHeroCityReport report = new CrossFiveHeroCityReport();
        CrossFiveHeroUserData userData = getUserData(userId);
        UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(userId);
        if(userBaseInfo == null){
            return null;
        }
        report.setGroupId(groupId);
        report.setActivityId(config.getActivityId());
        report.setCityId(cityId);
        report.setBattleCount(killCount);
        report.setIsRob(isRob);
        report.setCampId(userData.getCampId());
        report.setUserId(userId);
        report.setNickName(userBaseInfo.getNickName());
        report.setDecoration(userBaseInfo.getDecoration());
        report.setDefCampId(campId);
        report.setBeAttTokenNickName(nickName);
        report.setTime(System.currentTimeMillis());
        if(cityId == luoyangId){
            if(cityReportLuoYangList.size() >= config.getCityReportNum()){
                cityReportLuoYangList.sort(new CityReportSort());
                cityReportLuoYangList.remove(cityReportLuoYangList.size() - 1);
            }
            cityReportLuoYangList.add(report);
            for(CrossFiveHeroUserData uu : userDataMap.values()){
                addRedDot(uu.getUserId(), eFiveHeroRedDotType.Type3_CityLuoYangReport);
            }
        }else{
            if(cityReportList.size() >= config.getCityReportNum()){
                cityReportList.sort(new CityReportSort());
                cityReportList.remove(cityReportList.size() - 1);
            }
            cityReportList.add(report);
            for(CrossFiveHeroUserData uu : userDataMap.values()){
                addRedDot(uu.getUserId(), eFiveHeroRedDotType.Type2_CityReport);
            }
        }

        addNeedInsertCityReportData(report);
        return report;
    }

    //要把防守门客弄成一定的顺序给不同的玩家打 再次筛选：把初步筛选的门客再按血量排序，均分成m个难度池，难度池有出战顺序。5|3|1|4|2
    //如果进攻方挑战失败。守军门客根据剩余血量重新排序筛选，血量为0则剔除池子。
    private  List<CrossFiveHeroBattlePatrons> makeUserBattleList(Map<Integer, CrossFiveHeroBattlePatrons> defPatronsMap,CrossFiveHeroCity city){
        List<CrossFiveHeroBattlePatrons> retList = new ArrayList<>();
        List<CrossFiveHeroBattlePatrons> allList = new ArrayList<>();
        Map<Integer,List<CrossFiveHeroBattlePatrons>> gropuListMap = new ConcurrentHashMap<>();
        allList = new ArrayList<>(defPatronsMap.values());
        allList.sort(new BattlePatronsBloodSort());
        int patronsCount = allList.size();
        //只有一个不灵活，策划说要配到地块类型那
//        List<Integer> indexList = config.getPatronsIndexList();
        FiveHeroTypeConfig typeConfig = config.getTypeConfigByCityId(city.getCityId());
        List<Integer> indexList = typeConfig.getPoolSelectList();
        //每一组多少个人
        int oneNum = patronsCount/indexList.size();
        if(patronsCount%indexList.size() != 0){
            oneNum = oneNum + 1;
        }
        for(int i = 1; i <= indexList.size(); i++){
            if(!gropuListMap.containsKey(i)){
                gropuListMap.put(i,new ArrayList<>());
            }
            while (allList.size() > 0){
                if(gropuListMap.get(i).size() < oneNum){
                    gropuListMap.get(i).add(allList.get(0));
                    allList.remove(0);
                }else{
                    break;
                }
            }
        }
        //随机一个
        for(int groupId : indexList){
            List<CrossFiveHeroBattlePatrons> pList = gropuListMap.get(groupId);
            if(pList == null || pList.size() == 0){
//                gropuListMap.remove(groupId);
                continue;
            }
            int index = randomHelper.next(0,pList.size());
            retList.add(pList.get(index));
            pList.remove(index);
        }
        //是不是所有组都在里面
        boolean allIn = true;
        for(int groupId : gropuListMap.keySet()){
            if(!indexList.contains(groupId)){
                allIn = false;
            }
        }
        if(allIn){
            while (gropuListMap.size() > 0){
                for(int groupId : indexList){
                    List<CrossFiveHeroBattlePatrons> pList = gropuListMap.get(groupId);
                    if(pList == null || pList.size() == 0){
                        gropuListMap.remove(groupId);
                        continue;
                    }
                    int index = randomHelper.next(0,pList.size());
                    retList.add(pList.get(index));
                    pList.remove(index);
                }
            }
        }else{
            //全部放进去
            for(int i = 1; i <= indexList.size(); i++){
                List<CrossFiveHeroBattlePatrons> pList = gropuListMap.get(i);
                retList.addAll(pList);
            }
        }


        return retList;
    }

    //获取所有门客能力值
    private long getAllPatronsBlood(long userId,CrossFiveHeroCity city){
        long allValue = 0;
        CrossFiveHeroUserData userData = getUserData(userId);
        Map<Integer, CrossFiveHeroPatrons> patronsMap = userData.getPatronsMap();
        for(CrossFiveHeroPatrons patrons : patronsMap.values()){
            long pv = getPatronsMaxBloodShield(patrons,city);
            allValue = allValue + pv;
        }
        return allValue;
    }

    private long getAllPatronsBlood(long userId){
        long allValue = 0;
        CrossFiveHeroUserData userData = getUserData(userId);
        Map<Integer, CrossFiveHeroPatrons> patronsMap = userData.getPatronsMap();
        for(CrossFiveHeroPatrons patrons : patronsMap.values()){
            long pv = getPatronsMaxBlood(patrons);
            allValue = allValue + pv;
        }
        return allValue;
    }

    private PatronsBattleDetail patronsBattle(CrossFiveHeroBattlePatrons myPatrons, CrossFiveHeroBattlePatrons enemyPatrons,CrossFiveHeroCity city) {

        PatronsBattleDetail battleDetail = new PatronsBattleDetail();

        long myDamage = myPatrons.getMaxBlood();
        long enemyDamage = enemyPatrons.getTempBattleBlood();
        long eCurrentBlood = enemyPatrons.getTempBattleBlood() - myDamage;
        long mCurrentBlood = myPatrons.getTempBattleBlood() - enemyDamage;
        enemyPatrons.setTempBattleBlood(eCurrentBlood);
        myPatrons.setTempBattleBlood(mCurrentBlood);

        battleDetail.setMyPatronsId(myPatrons.getId());
        battleDetail.setMyPatronsCurrentBlood(BigInteger.valueOf(mCurrentBlood));
        battleDetail.setMyPatronsTotalBlood(BigInteger.valueOf(myDamage));

        battleDetail.setEnemyPatronsId(enemyPatrons.getId());
        battleDetail.setEnemyPatronsCurrentBlood(BigInteger.valueOf(eCurrentBlood));
        battleDetail.setEnemyPatronsTotalBlood(BigInteger.valueOf(enemyPatrons.getMaxBlood()));

        battleDetail.setNo(enemyPatrons.getIndex());
        return battleDetail;
    }

    //排序返回玩家身上的门客,固定门客能力值，因为会自动升级
    private List<CrossFiveHeroBattlePatrons> getPatronsListSort(long userId,CrossFiveHeroCity city){
        List<CrossFiveHeroBattlePatrons> aaaList = new ArrayList<>();
        CrossFiveHeroUserData userData = getUserData(userId);
        Map<Integer, CrossFiveHeroPatrons> patronsMap = userData.getPatronsMap();
        LinkedList<CrossFiveHeroRank> patronsRankList = new LinkedList<>();
        Map<Integer, CrossFiveHeroBattlePatrons> bpMap = new ConcurrentHashMap<>();
        for(CrossFiveHeroPatrons patrons : patronsMap.values()){
            long maxBlood = getPatronsMaxBloodShield(patrons,city);
            CrossFiveHeroBattlePatrons  bp = new CrossFiveHeroBattlePatrons();
            bp.setUserId(patrons.getUserId());
            bp.setId(patrons.getId());
            bp.setSkin(patrons.getSkin());
            bp.setMaxBlood(maxBlood);
            bp.setNowBlood(maxBlood);
            bpMap.put(bp.getId(),bp);
            patronsRankList.add(new CrossFiveHeroRank(patrons.getId() + "",bp.getMaxBlood(),0));
        }
        patronsRankList.sort(new CrossFiveHeroRankSort());
        for(CrossFiveHeroRank rank : patronsRankList){
            aaaList.add(bpMap.get(Integer.valueOf(rank.getId())));
        }
        return aaaList;
    }

    //计算pvp产生了多少名望值 （参数1/参数2）*(连胜数*连胜积分)^（参数3/参数4）*体力消耗
    private int pvpPopValue(int winCount,int cityId){
        FiveHeroCityConfig cityConfig = config.getCityConfig(cityId);
        FiveHeroTypeConfig typeConfig = config.getTypeConfigByCityId(cityId);
        int param1 = config.getPopParamValue(0);
        int param2 = config.getPopParamValue(1);
        int param3 = config.getPopParamValue(2);
        int param4 = config.getPopParamValue(3);
        int param5 = config.getPopParamValue(4);
        int param6 = config.getPopParamValue(5);
        int param7 = config.getPopParamValue(6);
        int param8 = config.getPopParamValue(7);
        int winPop = config.getPopValue(cityConfig.getType());
        int winMaxPop = config.getPopMaxValue(cityConfig.getType());
        double value1 = winCount * winPop;
        if(param2 == 0)param2 = 1;
        if(param4 == 0)param4 = 1;
        if(param6 == 0)param6 = 1;
        if(param8 == 0)param8 = 1;
        BigDecimal zhishu = BigDecimal.valueOf(param3).divide(BigDecimal.valueOf(param4),4,BigDecimal.ROUND_HALF_UP);
        value1 = Math.pow(value1,zhishu.doubleValue());
        BigDecimal result = BigDecimal.valueOf(param1).divide(BigDecimal.valueOf(param2),4,BigDecimal.ROUND_HALF_UP);
        result = result.multiply(BigDecimal.valueOf(value1));
        if(result.longValue() > winMaxPop + 1){
            value1 = winCount * winPop;
            zhishu = BigDecimal.valueOf(param7).divide(BigDecimal.valueOf(param8),4,BigDecimal.ROUND_HALF_UP);
            value1 = Math.pow(value1,zhishu.doubleValue());
            result = BigDecimal.valueOf(param5).divide(BigDecimal.valueOf(param6),4,BigDecimal.ROUND_HALF_UP);
            result = result.multiply(BigDecimal.valueOf(value1));
            result = result.add(BigDecimal.valueOf(winMaxPop));
        }
        result = result.multiply(BigDecimal.valueOf(typeConfig.getEnergyCost())).setScale(0,BigDecimal.ROUND_HALF_UP);

        return Math.max(result.intValue(),30);
    }

    //又要一个一个打
    private FiveHeroProto.FiveHeroEventPvpMsg.Builder eventBattleV6(long userId,int eventId,CrossFiveHeroCity city){
        //打之前是哪个阵营的
        int oCampId = city.getCampId();
        long oOccUserId = city.getOccUserId();
        FiveHeroProto.FiveHeroEventPvpMsg.Builder battlePatronsMsg = FiveHeroProto.FiveHeroEventPvpMsg.newBuilder();
        List<CrossFiveHeroBattlePatrons> battlePatronsList = getPatronsListSort(userId,city);
        long allValue = 0;
        for(CrossFiveHeroBattlePatrons bp : battlePatronsList){
            FiveHeroProto.FiveHeroEventPvpPatronsMsg.Builder patronsMsg = FiveHeroProto.FiveHeroEventPvpPatronsMsg.newBuilder();
            patronsMsg.setPatronsId(bp.getId());
            patronsMsg.setSkinId(bp.getSkin());
            patronsMsg.setMaxBlood(bp.getMaxBlood() + "");
            battlePatronsMsg.addUserPatrons(patronsMsg);
            //总能力值
            allValue = allValue + bp.getMaxBlood();
            //射一下打的血量，打的时候扣这个
            bp.setTempBattleBlood(bp.getNowBlood());
        }
        battlePatronsMsg.setBlood(String.valueOf(allValue));
        //每次打都是全新的门客
        Map<Integer, CrossFiveHeroBattlePatrons> defPatronsMap = city.getDefPatronsMap();
        FiveHeroCityConfig cityConfig = config.getCityConfig(city.getCityId());
//        Map<Integer,CrossFiveHeroBattlePatrons> defPatronsMap = getRandomPatronsPvpV2(cityConfig,getUserData(city.getOccUserId()));
        //todo-xx 多了一个增加自有领地BUFF
        List<Integer> jList = cityConfig.getJobBuffEffectList();
        BigDecimal mValue = BigDecimal.valueOf(1000);
        if(jList.size() > 3 && jList.get(3) > 0 && city.getCampId() == jList.get(2)){
            mValue = mValue.add(BigDecimal.valueOf(jList.get(3)));
            for(CrossFiveHeroBattlePatrons p : defPatronsMap.values()){
                BigDecimal newValue = BigDecimal.valueOf(p.getAbility());
                newValue = newValue.multiply(mValue).divide(BigDecimal.valueOf(1000),0,BigDecimal.ROUND_UP);
                p.setMaxBlood(newValue.longValue());
                p.setNowBlood(newValue.longValue());
            }
        }
        List<CrossFiveHeroBattlePatrons> defIndexPatronsList = makeUserBattleList(defPatronsMap,city);
        List<CrossFiveHeroBattlePatrons> enemyPatronsList = new ArrayList<>(defIndexPatronsList);
        //todo-xx 血量
        battlePatronsMsg.setTeamCount(city.getKillCountMap().getOrDefault(1L,0));
        BattleResult battleResult = new BattleResult();
        for(CrossFiveHeroBattlePatrons p : enemyPatronsList){
            p.setTempBattleBlood(p.getNowBlood());
        }
        //校验
        long checkAllSelfValue = 0;
        List<Integer> checkBattleNoList = new ArrayList<>();
        List<Integer> checkDefNoList = new ArrayList<>();
        List<Integer> checkDefAllValueList = new ArrayList<>();
        int killCount = 0;
        while(true){
            PatronsBattleDetail patronsBattleDetail = null;
            if(battlePatronsList.size() > 0 && enemyPatronsList.size() > 0){
                patronsBattleDetail = patronsBattle(battlePatronsList.get(0), enemyPatronsList.get(0),city);
                if(!checkBattleNoList.contains(enemyPatronsList.get(0).getIndex())){
                    checkBattleNoList.add(enemyPatronsList.get(0).getIndex());
                }
                if(!checkDefAllValueList.contains(battlePatronsList.get(0).getId())){
                    checkDefAllValueList.add(battlePatronsList.get(0).getId());
                    checkAllSelfValue = checkAllSelfValue + patronsBattleDetail.getMyPatronsTotalBlood().longValue();
                }
            }
            if(patronsBattleDetail != null) {
                battleResult.getPatronsBattleDetailList().add(patronsBattleDetail);
                if (patronsBattleDetail.getMyPatronsCurrentBlood().compareTo(BigInteger.ZERO) <= 0) {
                    battlePatronsList.remove(0);
                }
                if (patronsBattleDetail.getEnemyPatronsCurrentBlood().compareTo(BigInteger.ZERO)<= 0) {
                    killCount++;

                    enemyPatronsList.remove(0);
                }
            }
            //全部打完则退出战斗
            if (battlePatronsList.size() == 0) {//对方获胜
                battleResult.setWinUserId(oOccUserId);
                break;
            }

            if (enemyPatronsList.size() == 0) {
                battleResult.setWinUserId(userId);
                break;
            }
        }
        List<Integer> dieIndexList = new ArrayList<>();
        LinkedList<CrossFiveHeroBattlePatrons> dieList = city.getDiePatronsList();
        for(int i = 0;i < killCount + 5;i++){
            if(i >= defIndexPatronsList.size()){
                continue;
            }
            CrossFiveHeroBattlePatrons defPatrons = defIndexPatronsList.get(i);
            FiveHeroProto.FiveHeroEventPvpPatronsMsg.Builder patronsMsg = FiveHeroProto.FiveHeroEventPvpPatronsMsg.newBuilder();
            patronsMsg.setIndex(defPatrons.getIndex());
            patronsMsg.setPatronsId(defPatrons.getId());
            patronsMsg.setSkinId(defPatrons.getSkin());
            UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(defPatrons.getUserId());
            String nickName = "防守军";
            if(userBaseInfo == null){
                logger.debug("找不到玩家数据了{}",defPatrons.getUserId());
            }else{
                nickName = userBaseInfo.getNickName();
            }
            patronsMsg.setNickName(nickName);
            patronsMsg.setMaxBlood(String.valueOf(defPatrons.getMaxBlood()));
            patronsMsg.setOBlood(String.valueOf(defPatrons.getNowBlood()));
            patronsMsg.setNBlood(String.valueOf(defPatrons.getTempBattleBlood()));
            battlePatronsMsg.addPatrons(patronsMsg);
            //改成不掉血了
            if(defPatrons.getTempBattleBlood() <= 0){
//                dieIndexList.add(defPatrons.getIndex());
//                dieList.add(defPatrons);
            }else{
//                defPatrons.setNowBlood(defPatrons.getTempBattleBlood());
            }
            checkDefNoList.add(defPatrons.getIndex());
        }
        battlePatronsMsg.setBattleDetailList(BattlePb.parseBattleDetailListMsg(battleResult.getPatronsBattleDetailList()));
        //*************************************校验******************************************************************
        for(int index : checkBattleNoList){
            if(!checkDefNoList.contains(index)){
                logger.debug("战斗中的门客没有在防守门客下{}",index);
            }
        }
        //todo-xx 去掉，弄了打快点
//        killCount = killCount * 100;
        //*************************************校验******************************************************************

        for(int dieIndex : dieIndexList){
            defPatronsMap.remove(dieIndex);
        }
        /*int param1 = 14341;
        int param2 = 10000;
        int param3 = 5250;
        int param4 = 10000;
        int param5 = 37900;
        int param6 = 10000;
        int param7 = 100000;
        int param8 = 10000;*/
        int param1 = config.getAttParamValue(0);
        int param2 = config.getAttParamValue(1);
        int param3 = config.getAttParamValue(2);
        int param4 = config.getAttParamValue(3);
        int param5 = config.getAttParamValue(4);
        int param6 = config.getAttParamValue(5);
        int param7 = config.getAttParamValue(6);
        int param8 = config.getAttParamValue(7);
        int winPop = config.getPopValue(cityConfig.getType());
        double value1 = killCount * winPop;
        BigDecimal zhishu = BigDecimal.valueOf(param3).divide(BigDecimal.valueOf(param4),10,BigDecimal.ROUND_HALF_UP);
        value1 = Math.pow(value1,zhishu.doubleValue());
        BigDecimal result = BigDecimal.valueOf(param1).divide(BigDecimal.valueOf(param2),10,BigDecimal.ROUND_HALF_UP);
        BigDecimal value56 = BigDecimal.valueOf(param5).divide(BigDecimal.valueOf(param6),10,BigDecimal.ROUND_HALF_UP);
        BigDecimal value78 = BigDecimal.valueOf(param7).divide(BigDecimal.valueOf(param8),10,BigDecimal.ROUND_HALF_UP);
        result = result.multiply(BigDecimal.valueOf(value1));
        result = result.subtract(value56);
        result = result.multiply(value78).setScale(0,BigDecimal.ROUND_UP);
        Map<Integer,Map<Integer,Integer>> distanceMap = FiveHeroMapLogic.getCityDistanceMap(config.getCityConfigMap());
        Map<Integer,Integer> campdistanceMap = distanceMap.get(city.getCityId());
        CrossFiveHeroUserData userData = getUserData(userId);
        int moraleRate = config.getMoraleRate(campdistanceMap.get(userData.getCampId()));
        result = result.multiply(BigDecimal.valueOf(moraleRate)).divide(BigDecimal.valueOf(1000),10,BigDecimal.ROUND_UP);
        int reduceHp = Math.max(result.intValue(),1);
        battlePatronsMsg.setReduceBlood(reduceHp);
        //todo-xx 掉血公式
        Map<Long, Integer> killMap = city.getKillCountMap();
        if(killMap.getOrDefault(1L,0) - reduceHp <= 0){
            battlePatronsMsg.setRob(true);
            city.getKillCountMap().clear();
            robSuccess(city,userData.getCampId(),userId);
        }else{
            battlePatronsMsg.setRob(false);
//            city.setDefPatronsMap(defPatronsMap);
//            city.setDiePatronsList(dieList);
            //todo-xx 掉血公式
            killMap.put(1L,killMap.getOrDefault(1L,0) - reduceHp);

            Map<Long, Integer> killCountMap = city.getKillCountMap();
            killCountMap.put(userId,killCountMap.getOrDefault(userId,0) + killCount);
        }
        /*if(battleResult.getWinUserId() == userId){

        }else{

        }*/
        addNeedUpdateCityData(city);

        FiveHeroEventConfig eventConfig = config.getEventConfig(eventId);
        Property winReward = PropertyHelper.parseNewStringToProperty(eventConfig.getWinRewards());
        winReward.goodCountMultiNum(killCount);
        int popValue = pvpPopValue(killCount,city.getCityId());
        if(popValue > 0){
            String popReward = config.getPopularityItemId() + "=" + popValue;
            winReward.addProperty(PropertyHelper.parseStringToProperty(popReward));
        }
        winReward.addProperty(PropertyHelper.parseNewStringToProperty(eventConfig.getRewards()));
        String attReward = PropertyHelper.parsePropertyToString(winReward);
        String robReward = "";
        if(battlePatronsMsg.getRob()){
            robReward = PropertyHelper.parsePropertyToString(PropertyHelper.parseNewStringToProperty(eventConfig.getKillRewards()));
        }
        battlePatronsMsg.setBeatCount(killCount);
        battlePatronsMsg.setAttReward(attReward);
        battlePatronsMsg.setRobReward(robReward);

        String nickName = "";
        if(oOccUserId != 0){
            UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(oOccUserId);
            if(userBaseInfo != null){
                nickName = userBaseInfo.getNickName();
            }
        }
        makeUserReport(userId,city.getCityId(),oCampId,killCount,attReward,robReward,nickName);
        //地块变更战报
        if(config.getCityChangeON() == 1 && battlePatronsMsg.getRob()){
            makeCityReport(userId,city.getCityId(),oCampId,killCount,battlePatronsMsg.getRob()?1:0,"");
        }
        //击杀战报
        /*if(config.getCityKillON() == 1 && killCount >= config.getCityKillNum()){
            //人数击杀的一定都是没占领，客户端用这个判断的
            makeCityReport(userId,city.getCityId(),oCampId,killCount,0,"");
        }*/
        //系统击杀公告
        if(config.getSystemKillON() == 1 && killCount >= config.getSystemKillNum(cityConfig.getType())){
            UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(userId);
            if(userBaseInfo != null && userData != null){
                addSystemChat(eMessageType.FiveHeroSystemChat4, config.getActivityId(),
                        userData.getCampId() + GameConfig.TALK_SEPARATOR + userBaseInfo.getNickName() + GameConfig.TALK_SEPARATOR + killCount + GameConfig.TALK_SEPARATOR + city.getCityId(),System.currentTimeMillis(),userId);
            }
        }
        //系统球员公告
        if(config.getSystemCampON() == 1 && battlePatronsMsg.getRob() && oCampId != 0){
            addSystemChat(eMessageType.FiveHeroSystemChat2, oCampId,
                    "" + city.getCityId(),System.currentTimeMillis(),0);
        }
        //系统地块变更公告
        if(config.getSystemChangeON() == 1 && battlePatronsMsg.getRob()){
            UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(userId);
            if(userBaseInfo != null){
                addSystemChat(eMessageType.FiveHeroSystemChat3, config.getActivityId(),
                        city.getCampId() + GameConfig.TALK_SEPARATOR + userBaseInfo.getNickName() + GameConfig.TALK_SEPARATOR + city.getCityId(),System.currentTimeMillis(),0);
            }
        }
        //跑马灯地块变更公告
        if(config.getLampChangeON() == 1 && battlePatronsMsg.getRob()){
            CrossFiveHeroHorseLamp lamp = new CrossFiveHeroHorseLamp();
            lamp.setAttUserId(userId);
            lamp.setDefUserId(oOccUserId);
            lamp.setKillNum(killCount);
            lamp.setTokenNum(0);
            lamp.setType(1);
            lamp.setTime(System.currentTimeMillis());
            lamp.setCityId(city.getCityId());
            addHorseLamp(lamp);//添加跑马灯
        }
        //跑马灯击杀公告
        if(config.getLampKillON() == 1 && killCount >= config.getLampKillNum(cityConfig.getType()) && isTopKill(userId,cityConfig.getType(),killCount)){
            CrossFiveHeroHorseLamp lamp = new CrossFiveHeroHorseLamp();
            lamp.setAttUserId(userId);
            lamp.setDefUserId(city.getOccUserId());
            lamp.setKillNum(killCount);
            lamp.setTokenNum(0);
            lamp.setType(2);
            lamp.setTime(System.currentTimeMillis());
            lamp.setCityId(city.getCityId());
            addHorseLamp(lamp);//添加跑马灯
        }
        return battlePatronsMsg;
    }

    //其他阵营的战令
    private List<CrossFiveHeroToken> getOtherCampTokenList(CrossFiveHeroCity city, int campId){
        Map<Integer, CrossFiveHeroToken> tokenMap = city.getDefTokenMap();
        List<CrossFiveHeroToken> tokenList = new ArrayList<>();
        for(CrossFiveHeroToken token : tokenMap.values()){
            if(token.getCampId() != campId){
                tokenList.add(token);
            }
        }
        return tokenList;
    }
    //是人的，测试用
    private List<CrossFiveHeroToken> getOtherCampUserTokenList(CrossFiveHeroCity city, int campId){
        Map<Integer, CrossFiveHeroToken> tokenMap = city.getDefTokenMap();
        List<CrossFiveHeroToken> tokenList = new ArrayList<>();
        List<CrossFiveHeroToken> tokenUserList = new ArrayList<>();
        for(CrossFiveHeroToken token : tokenMap.values()){
            if(token.getCampId() != campId){
                tokenList.add(token);
                if(token.getUserId() != 0){
                    tokenUserList.add(token);
                }
            }
        }
        if(tokenUserList.size() > 0){
            return tokenUserList;
        }
        return tokenList;
    }


    //阵营经验值加上去
    private void checkExpAdd(){
        long nowTime = System.currentTimeMillis();
        if(!ActivityHelper.activityInTime(getActivityInfo())){
            return;
        }
        //结束了不加经验
        if(nowTime > config.getTodayOutSideOverTime()){
            setMingtianExpTime();
            return;
        }
        //锁一下触发下经验，不会炸吧，算了，不锁了
        Map<Integer,Integer> campAddPerMap = new ConcurrentHashMap<>();
        Map<Integer,Map<Integer,Integer>> addCityMap = getCampExpAddMap();
        Map<Integer,Integer> addMap = new ConcurrentHashMap<>();
        for(int campId : addCityMap.keySet()){
            int value = 0;
            Map<Integer,Integer> cityMap = addCityMap.get(campId);
            for(int cityId : cityMap.keySet()){
                value = value + cityMap.get(cityId);
            }
            addMap.put(campId,value);
        }

        int maxpExpValue = config.getMaxTechExp();
        synchronized (crossFiveHeroMatchData){
            if(addMap.size() > 0){
                Map<Integer, Integer> expMap = crossFiveHeroMatchData.getExpMap();
                Map<Integer, Integer> expLevelMap = crossFiveHeroMatchData.getExpLevelMap();
                for(int campId : addMap.keySet()){
                    int nowValue = expMap.getOrDefault(campId,0);
                    if(nowValue + addMap.get(campId) >= maxpExpValue){
                        nowValue = maxpExpValue;
                    }else{
                        nowValue = expMap.getOrDefault(campId,0) + addMap.get(campId);
                    }
                    expMap.put(campId,nowValue);
                    int level = expLevelMap.getOrDefault(campId,0);
                    int nowLevel = config.getTechLevel(nowValue);
                    expLevelMap.put(campId,nowLevel);
                    if(level != nowLevel){
                        int addPer = config.getTechLevelUpAddPer(level,nowLevel);
                        if(addPer > 0){
                            campAddPerMap.put(campId,addPer);
                        }
                        addCityChange(config.getCampMainCityId(campId));
                    }
                    List<Integer> cityIdList = new ArrayList<>(addCityMap.get(campId).keySet());
                    CrossAutoLogMgr.add(new LogFiveHeroTech(
                            groupId,
                            config.getActivityInfo().getActivityId(),
                            campId,
                            addMap.get(campId),
                            nowValue,
                            StringUtils.listToString(cityIdList,"|"),
                            nowLevel
                    ));
                }
                crossFiveHeroMatchData.setExpMap(expMap);
                crossFiveHeroMatchData.setExpLevelMap(expLevelMap);
            }
        }

        //门客加能力值
        for(int campId : campAddPerMap.keySet()){
            logger.debug("{}阵营自动升级了,加了{}百分比",campId,campAddPerMap.get(campId));
            int addPerValue = campAddPerMap.get(campId);
            for(CrossFiveHeroUserData userData : userDataMap.values()){
                if(userData.getCampId() == campId){
                    //加锁
                    Map<Integer, CrossFiveHeroPatrons> pMap = userData.getPatronsMap();
                    for(CrossFiveHeroPatrons p : pMap.values()){
                        if(p.getNowBlood() != 0 || p.getType4nowBlood() != 0){
                            synchronized (p){
                                BigDecimal value = BigDecimal.valueOf(p.getAbility());
                                value = value.multiply(BigDecimal.valueOf(addPerValue)).divide(BigDecimal.valueOf(1000),0,BigDecimal.ROUND_UP);
                                if(p.getNowBlood() != 0){
                                    p.setNowBlood(p.getNowBlood() + value.longValue());
                                }
                                if(p.getType4nowBlood() != 0){
                                    p.setType4nowBlood(p.getType4nowBlood() + value.longValue());
                                }
                                fhAc.addNeedUpdatePatronsData(p);
                            }
                            BigDecimal value = BigDecimal.valueOf(p.getAbility());
                            value = value.multiply(BigDecimal.valueOf(addPerValue)).divide(BigDecimal.valueOf(1000),0,BigDecimal.ROUND_UP);
                            long maxB = getPatronsMaxBlood(p);
                            /*CrossFiveHeroLog.addLogFiveHeroPatronsUpdate(new LogFiveHeroPatronsUpdate(
                                    groupId,
                                    config.getActivityInfo().getActivityId(),
                                    p.getUserId(),
                                    userData.getCampId(),
                                    p.getId(),
                                    3,
                                    value.longValue(),
                                    maxB - value.longValue(),
                                    maxB
                            ));*/
                        }
                    }
                }
            }

            for(CrossFiveHeroUserData userData : userDataMap.values()){
                if(userData.getCampId() == campId){
                    long addZhanli = getAllAddValueLevelUp(userData.getUserId(),addPerValue);
                    syncUserDataMsg(userData.getUserId(),addZhanli);
                }
            }
        }
    }

    //被打了加一下经验
    private void checkExpAdd(CrossFiveHeroCity city){
        int campId = city.getCampId();
        int addValue = cityExpAdd(city);
        synchronized (crossFiveHeroMatchData){
            Map<Integer, Integer> expMap = crossFiveHeroMatchData.getExpMap();
            int oValue = expMap.getOrDefault(campId,0);
            expMap.put(campId,oValue + addValue);
            crossFiveHeroMatchData.setExpMap(expMap);
        }
    }

    //每天晚上洛阳城结束了收回
    private void checkTokenDayBack(){
        if(!ActivityHelper.activityInTime(getActivityInfo())){
            return;
        }
        long todayInSideOverTime = config.getTodayInSideOverTime();
        //五分钟后才开始撤回
        if(System.currentTimeMillis() <= todayInSideOverTime && !isTodayTokenScoreOver()){
            return;
        }
        boolean makeNew = false;
        Map<Integer, CrossFiveHeroCity> cityMap = crossFiveHeroMatchData.getCityMap();
        int luoYangId = config.getLuoYangId();
        CrossFiveHeroCity luoYangCity = cityMap.get(luoYangId);
        FiveHeroCityConfig luoyangCityConfig = config.getCityConfig(luoYangId);
        Map<Integer, CrossFiveHeroToken> tokenMap = luoYangCity.getDefTokenMap();
        for(CrossFiveHeroToken token : tokenMap.values()){
            synchronized (getCityTokenLock(token.getTokenId())){
                if(token.getCampId() != 0){
                    LogFiveHeroToken tokenLog = tokenChangeOwner(2,token,token.getValue(),null);
                    CrossFiveHeroUserData userData = getUserData(token.getUserId());
                    userData.addLogToken(tokenLog);
                    makeNew = true;
                    CrossFiveHeroUserData tokenUserData = getUserData(token.getUserId());
                    if(tokenUserData != null){
                        Map<Integer, CrossFiveHeroPatrons> pMap = tokenUserData.getPatronsMap();
                        if(pMap.containsKey(token.getDefPatrons().getId())){
                            pMap.get(token.getDefPatrons().getId()).setTokenId(0);
                        }
                    }
                }
            }
        }
        if(makeNew){
            Map<Integer,CrossFiveHeroToken> newTokenMap = getRandomTokenLuoYang(luoyangCityConfig);
            luoYangCity.setDefTokenMap(newTokenMap);
            addNeedUpdateCityData(luoYangCity);
        }
    }

    //小到大
    static class TokenTimeSort implements Comparator<CrossFiveHeroToken> {
        @Override
        public int compare(CrossFiveHeroToken o1, CrossFiveHeroToken o2) {
            if (o1.getGetTime() == o2.getGetTime()) {
                return 0;
            }
            if (o1.getGetTime() < o2.getGetTime()) {
                return -1;
            }
            return 1;
        }
    }

    //收货战令收益
    private void checkTokenGetReward(){
        if(!ActivityHelper.activityInTime(getActivityInfo())){
            return;
        }
        Map<Integer, CrossFiveHeroCity> cityMap = crossFiveHeroMatchData.getCityMap();
        int luoYangId = config.getLuoYangId();
        CrossFiveHeroCity luoYangCity = cityMap.get(luoYangId);
        Map<Integer, CrossFiveHeroToken> tokenMap = luoYangCity.getDefTokenMap();
        List<CrossFiveHeroToken> tokenList = new ArrayList<>(tokenMap.values());
        tokenList.sort(new TokenTimeSort());
        boolean isUpdate = false;
        //是不是要同步阵营积分
        boolean isSyncScore = false;
        long nowTime = System.currentTimeMillis();
        Map<Integer,Map<Integer,Long>> campTokenAddValueMap = new ConcurrentHashMap<>();
        for(CrossFiveHeroToken token : tokenList){
            //先拿了，这里变了没关系，就没有收益了
            int tokenId = token.getTokenId();
            int campId = token.getCampId();
            long addValue = tokenGetReward(token);
            if(addValue > 0){
                if(!campTokenAddValueMap.containsKey(campId)){
                    campTokenAddValueMap.put(campId,new ConcurrentHashMap<>());
                }
                campTokenAddValueMap.get(campId).put(tokenId,addValue);
                isUpdate = true;
                isSyncScore = true;
            }
            //五秒钟之前的占领当初有变动，积分速度变了也要同步
            if(!isSyncScore && nowTime - token.getGetTokenTime() <= DateHelper.SECOND_MILLIONS * 5){
                isSyncScore = true;
            }
        }
        if(isUpdate){
            addNeedUpdateCityData(luoYangCity);
            for(int campId : campTokenAddValueMap.keySet()){
                long addValue = 0;
                for(long value : campTokenAddValueMap.get(campId).values()){
                    addValue = addValue + value;
                }
                List<Integer> tokenIdList = new ArrayList<>(campTokenAddValueMap.get(campId).keySet());
                Map<Integer, Long> allScoreMap = crossFiveHeroMatchData.getScoreMap();
                CrossAutoLogMgr.add(new LogFiveHeroScore(
                        groupId,
                        config.getActivityInfo().getActivityId(),
                        campId,
                        0,
                        2,
                        StringUtils.listToString(tokenIdList,"|"),
                        addValue,
                        allScoreMap.getOrDefault(campId,0L)
                ));
            }
        }
        if(isSyncScore){
            syncCampTokenScore(0);
        }
    }
    //在的阵营的一起同步了
    private void syncCampTokenScore(int campId){
        for(long userId : new ArrayList<>(inEnterUserIdList)){
            syncTokenScore(userId,false);
        }
    }

    //单个战令获得收益 增加的是积分
    private long tokenGetReward(CrossFiveHeroToken token){
        if(isTodayTokenScoreOver()){
            return 0;
        }
        long userId = 0;
        long addValue = 0;
        int matchDay = config.getMatchDay();
        synchronized (getCityTokenLock(token.getTokenId())){
            long nowTime = System.currentTimeMillis();
            if(token.getCampId() == 0){
                return addValue;
            }
            if(nowTime - token.getGetTime() < config.getTokenGetRewardCd()){
                return addValue;
            }
            long passTime = nowTime - token.getGetTime();
            long getTimes = passTime/config.getTokenGetRewardCd();
            FiveHeroOrderConfig orderConfig = config.getOrderConfig(token.getTokenId());
            addValue = getTimes * orderConfig.getRecoverNum();
            token.setValue(token.getValue() + (int)addValue);
            token.setGetTime(token.getGetTime() + getTimes * config.getTokenGetRewardCd());
            userId = token.getUserId();
        }
        if(addValue > 0){
            Map<Integer, Long> allScoreMap = crossFiveHeroMatchData.getScoreMap();
            synchronized (allScoreMap){
                Map<Integer, Map<Integer, Long>> scoreTokenMap = crossFiveHeroMatchData.getScoreTokenMap();
                if(!scoreTokenMap.containsKey(token.getCampId())){
                    scoreTokenMap.put(token.getCampId(),new ConcurrentHashMap<>());
                }
                Map<Integer, Long> dayScoreMap = scoreTokenMap.get(token.getCampId());
                long nowValue = dayScoreMap.getOrDefault(matchDay,0L);
                if(nowValue + addValue > config.getLuoYangOverScore()){
                    addValue = config.getLuoYangOverScore() - nowValue;
                }
                if(config.getLampTokenScoreON() == 1 &&
                        ((nowValue < config.getLampTokenScoreMin() && nowValue + addValue >= config.getLampTokenScoreMin()) ||
                                (nowValue < config.getLampTokenScoreMax() && nowValue + addValue >= config.getLampTokenScoreMax()))){
                    CrossFiveHeroHorseLamp lamp = new CrossFiveHeroHorseLamp();
                    lamp.setAttUserId(token.getCampId());
                    lamp.setDefUserId(0);
                    lamp.setKillNum(0);
                    lamp.setTokenNum((int)(nowValue + addValue));
                    lamp.setType(4);
                    lamp.setTime(System.currentTimeMillis());
                    lamp.setCityId(0);
                    addHorseLamp(lamp);//添加跑马灯
                }
                CrossFiveHeroUserData userData = getUserData(userId);
                userData.setScore(userData.getScore() + (int)addValue);
                Map<Integer, Long> tokenScoreMap = userData.getTokeScoreMap();
                tokenScoreMap.put(matchDay,tokenScoreMap.getOrDefault(matchDay,0L) + addValue);
                Map<Integer, CrossFiveHeroPatrons> patronsMap = userData.getPatronsMap();
                CrossFiveHeroPatrons patrons = patronsMap.get(token.getDefPatrons().getId());
                patrons.setTokenIntegral(patrons.getTokenIntegral() + (int)addValue);
                fhAc.addNeedUpdateUserData(userData);

                Long value = allScoreMap.getOrDefault(token.getCampId(),0L);
                value = value + addValue;
                allScoreMap.put(token.getCampId(),value);
                crossFiveHeroMatchData.setScoreMap(allScoreMap);
                dayScoreMap.put(matchDay,dayScoreMap.getOrDefault(matchDay,0L) + addValue);
                crossFiveHeroMatchData.setScoreTokenMap(scoreTokenMap);
            }
        }
        return addValue;
    }

    //被占领了加个日志，或者最后撤回了
    private LogFiveHeroToken tokenChangeOwner(int type,CrossFiveHeroToken token,int addValue,CrossFiveHeroBattlePatrons defPatrons){
        long nowTime = System.currentTimeMillis();
        LogFiveHeroToken log = new LogFiveHeroToken();
        log.setActivityId(config.getActivityId());
        log.setUserId(token.getUserId());
        log.setCampId(token.getCampId());
        log.setPatronsId(token.getDefPatrons().getId());
        log.setTokenId(token.getTokenId());
        log.setAddValue(addValue);
        if(defPatrons != null){
            log.setAttUserId(defPatrons.getUserId());
            log.setAttPatronsId(defPatrons.getId());
        }else{
            log.setAttUserId(0);
            log.setAttPatronsId(0);
        }
        log.setType(type);
        log.setHasTime(nowTime - token.getGetTokenTime());
        log.setTime(nowTime);
        return log;
    }

    //被打下来的同步
    public void syncLuoYangBeAttack(CrossFiveHeroToken token,CrossFiveHeroBattlePatrons defPatrons,long selfTime,int addValue){
        FiveHeroProto.FiveHeroLuoYangResult.Builder respMsg = FiveHeroProto.FiveHeroLuoYangResult.newBuilder();
        FiveHeroProto.FiveHeroLuoYangPatronsResult.Builder tokenMsg = FiveHeroProto.FiveHeroLuoYangPatronsResult.newBuilder();
        tokenMsg.setTokenId(token.getTokenId());
        tokenMsg.setTime((int)((token.getGetTokenTime() - selfTime)/1000));
        tokenMsg.setPatronsId(defPatrons.getId());
        tokenMsg.setValue(addValue);
        tokenMsg.setBeRob(true);
        tokenMsg.setNickName("");
        UserBaseInfo baseInfo = CrossUserMgr.getUserBaseInfo(token.getUserId());
        if(baseInfo != null){
            tokenMsg.setNickName(baseInfo.getNickName());
        }
        respMsg.addResultList(tokenMsg);
        sendPacket(ClientProtocol.U_FIVEHERO_GET_LUOYANG_RESULT, respMsg, defPatrons.getUserId());
    }

    //成功占领洛阳
    private void robSuccessLuoYang(CrossFiveHeroToken token,CrossFiveHeroPatrons patrons){
        int oCampId = token.getCampId();
        CrossFiveHeroUserData userData = getUserData(patrons.getUserId());
        CrossFiveHeroBattlePatrons defPatrons = token.getDefPatrons();
        CrossFiveHeroUserData defUserData = getUserData(defPatrons.getUserId());
        Map<Integer, CrossFiveHeroPatrons> defUserPatronsMap = defUserData.getPatronsMap();
        CrossFiveHeroPatrons defUserPatrons = defUserPatronsMap.get(defPatrons.getId());
        defUserPatrons.setTokenId(0);
        //死了。。。。
        //不会死了
//        defUserPatrons.setType4nowBlood(0);
        defUserPatrons.setType4lastReviveTime(System.currentTimeMillis());
        defUserData.setPatronsMap(defUserPatronsMap);
        patrons.setTokenId(token.getTokenId());
        int addValue = token.getValue();
        defUserData.setScore(defUserData.getScore() + addValue);
        CrossFiveHeroBattlePatrons battlePatrons = makeBattlePatrons(patrons,token.getTokenId());
        token.setUserId(patrons.getUserId());
        token.setCampId(userData.getCampId());
        token.setValue(0);
        token.setDefPatrons(battlePatrons);
        long selfGetTime = token.getGetTokenTime();
        token.setGetTime(System.currentTimeMillis());
        token.setGetTokenTime(System.currentTimeMillis());
        userData.setTokenTime(System.currentTimeMillis());
        fhAc.addNeedUpdateUserData(userData);
        fhAc.addNeedUpdatePatronsData(patrons);
        fhAc.addNeedUpdatePatronsData(defUserPatrons);
        //日志
        tokenChangeOwner(1,token,addValue,defPatrons);
        if(oCampId != 0){
            syncLuoYangBeAttack(token,defPatrons,selfGetTime,addValue);
        }
    }

    private FiveHeroProto.FiveHeroEventLuoYangMsg.Builder eventLuoYang(CrossFiveHeroPatrons patrons,int eventId,CrossFiveHeroCity city){
        Map<Integer, CrossFiveHeroToken> tokenMap = city.getDefTokenMap();
        CrossFiveHeroUserData userData = getUserData(patrons.getUserId());
        CrossFiveHeroToken token = tokenMap.get(userData.getEventTokenId());
        //打之前是哪个阵营的
        int oCampId = token.getCampId();
        long oOccUserId = token.getUserId();
        FiveHeroProto.FiveHeroEventLuoYangMsg.Builder luoyangMsg = FiveHeroProto.FiveHeroEventLuoYangMsg.newBuilder();
        luoyangMsg.setPatronsAbility(String.valueOf(getPatronsMaxBlood(patrons)));
        CrossFiveHeroBattlePatrons defPatrons = token.getDefPatrons();
        luoyangMsg.setMaxBlood(String.valueOf(defPatrons.getMaxBlood()));
        luoyangMsg.setNBlood(String.valueOf(defPatrons.getNowBlood()));
        long nBlood = getPatronsMaxBlood(patrons);
        long allBlood = nBlood;
        boolean isRob = false;
        //洛陽城市是不會掉血的，打得过就打得过，门客是作为防守在上面被打死了才会死
        if(defPatrons.getNowBlood() >= allBlood){
            defPatrons.setNowBlood(defPatrons.getNowBlood() - allBlood);
            luoyangMsg.setIsKill(false);
            luoyangMsg.setNewPatronId(patrons.getId());
            luoyangMsg.setNewPatronMaxBlood(getPatronsMaxBloodShield(patrons,city) + "");
        }else{
            long addValue = tokenGetReward(token);
            Map<Integer, Long> allScoreMap = crossFiveHeroMatchData.getScoreMap();
            CrossAutoLogMgr.add(new LogFiveHeroScore(
                    groupId,
                    config.getActivityInfo().getActivityId(),
                    token.getCampId(),
                    0,
                    2,
                    token.getTokenId() + "",
                    addValue,
                    allScoreMap.getOrDefault(token.getCampId(),0L)
            ));
            isRob = true;
            robSuccessLuoYang(token,patrons);
            CrossFiveHeroPatrons patronsNew = getUserTopCityPatrons(patrons.getUserId(),city);
            if(patronsNew != null){
                luoyangMsg.setNewPatronId(patronsNew.getId());
                luoyangMsg.setNewPatronMaxBlood(getPatronsMaxBloodShield(patronsNew,city) + "");
            }else{
                luoyangMsg.setNewPatronId(0);
                luoyangMsg.setNewPatronMaxBlood("0");
            }
            luoyangMsg.setIsKill(true);
            city.setDefTokenMap(tokenMap);
            addNeedUpdateCityData(city);
        }

        FiveHeroEventConfig eventConfig = config.getEventConfig(eventId);
        String attReward = "";
        String robReward = "";
        Property otherReward = PropertyHelper.parseNewStringToProperty(eventConfig.getRewards());
        if(isRob){
            robReward = PropertyHelper.parsePropertyToString(PropertyHelper.parseNewStringToProperty(eventConfig.getKillRewards()));
        }else{
            otherReward.addProperty(PropertyHelper.parseNewStringToProperty(eventConfig.getFailRewards()));
        }
        attReward = PropertyHelper.parsePropertyToString(otherReward);
        luoyangMsg.setAttReward(attReward);
        luoyangMsg.setWinReward(robReward);
        String nickName = "";
        if(oOccUserId != 0){
            UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(oOccUserId);
            if(userBaseInfo != null){
                nickName = userBaseInfo.getNickName();
            }
        }else{
            FiveHeroOrderConfig orderConfig = config.getOrderConfig(token.getTokenId());
            nickName = orderConfig.getTeamName();
            nickName = ServerLanguageMgr.getContent(nickName, userData.getLanguage());
        }
        if(isRob && oOccUserId != 0){
            int day=config.getMatchDay();
            //打赢的打一下日志
            logger.warn("{}第{}天战斗，战令{},玩家{}攻打玩家{},赢了",
                    getActivityInfo().getActivityId(),day,token.getTokenId(),patrons.getUserId(),oOccUserId);
        }
        if(isRob){
            //自己一条
            makeUserReport(patrons.getUserId(),city.getCityId(),oCampId,token.getTokenId(),attReward,robReward,nickName);
            //被打一条 默认守军不能有一条
            UserBaseInfo attUserBaseInfo = CrossUserMgr.getUserBaseInfo(patrons.getUserId());
            if(attUserBaseInfo != null && oOccUserId != 0){
                String attNickName = attUserBaseInfo.getNickName();
                makeUserReport(defPatrons.getUserId(),city.getCityId(),userData.getCampId(),token.getTokenId(),"","",attNickName);
            }
        }
//        makeCityReport(patrons.getUserId(),city.getCityId(),oCampId,0,isRob?1:0);
        //只有占领的牌子才会变
        if(config.getCityTokenON() == 1 && isRob && getUserTokenList(userData.getUserId()).size() >= config.getCityTokenNum()){
            makeCityReport(patrons.getUserId(),city.getCityId(),oCampId,token.getTokenId(),isRob?1:0,nickName);
        }

        int userTokenNum = getUserTokenList(userData.getUserId()).size();
        if(config.getSystemTokenON() == 1 && userTokenNum >= config.getSystemTokenNum()){
            UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(patrons.getUserId());
            if(userBaseInfo != null){
                addSystemChat(eMessageType.FiveHeroSystemChat5, config.getActivityId(),
                        userData.getCampId() + GameConfig.TALK_SEPARATOR  + userBaseInfo.getNickName() + GameConfig.TALK_SEPARATOR + userTokenNum,System.currentTimeMillis(),patrons.getUserId());
            }
        }

        if(config.getLampTokenON() == 1 && isRob && userTokenNum >= config.getLampTokenNum() && isTopToken(patrons.getUserId(),userTokenNum)){
            CrossFiveHeroHorseLamp lamp = new CrossFiveHeroHorseLamp();
            lamp.setAttUserId(patrons.getUserId());
            lamp.setDefUserId(city.getOccUserId());
            lamp.setKillNum(1);
            lamp.setTokenNum(userTokenNum);
            lamp.setType(3);
            lamp.setTime(System.currentTimeMillis());
            lamp.setCityId(city.getCityId());
            addHorseLamp(lamp);//添加跑马灯
        }
        userData.setLuoYangAttTimes(userData.getLuoYangAttTimes() + 1);
        fhAc.addNeedUpdateUserData(userData);
        syncUserDataMsg(userData.getUserId());


        Property allReward = new Property();
        if(!StringUtils.isNullOrEmpty(luoyangMsg.getAttReward())){
            allReward.addProperty(PropertyHelper.parseStringToProperty(luoyangMsg.getAttReward()));
        }
        if(!StringUtils.isNullOrEmpty(luoyangMsg.getWinReward())){
            allReward.addProperty(PropertyHelper.parseStringToProperty(luoyangMsg.getWinReward()));
        }
        CrossAutoLogMgr.add(new LogFiveHeroLuoYang(
                config.getActivityInfo().getActivityId(),
                groupId,
                userData.getUserId(),
                token.getTokenId(),
                userData.getCampId(),
                oOccUserId,
                oCampId,
                Long.valueOf(luoyangMsg.getPatronsAbility()),
                luoyangMsg.getIsKill()?0:defPatrons.getNowBlood(),
                Long.valueOf(luoyangMsg.getNBlood()),
                PropertyHelper.parsePropertyToString(allReward))
        );
        return luoyangMsg;
    }

    //山贼事件
    private FiveHeroProto.FiveHeroEventBanditMsg.Builder eventBandit(CrossFiveHeroPatrons patrons,long userId,int eventId,CrossFiveHeroCity city){
        FiveHeroProto.FiveHeroEventBanditMsg.Builder retMsg = FiveHeroProto.FiveHeroEventBanditMsg.newBuilder();
        FiveHeroEventConfig eventConfig = config.getEventConfig(eventId);
        BigInteger userPatronsAb = getOccPatronsAbAll(userId,city);
//        userPatronsAb = BigInteger.valueOf(getPatronsBloodShield(patrons,city));
        //又用所有门客打
        userPatronsAb = BigInteger.valueOf(getAllPatronsBlood(userId,city));
        Map<Integer, CrossFiveHeroBandit> banditMap = city.getBanditMap();
        CrossFiveHeroBandit bandit = banditMap.get(eventConfig.getParameterList().get(0));
        retMsg.setNBlood(bandit.getBlood().toString());
        BigDecimal mValue = BigDecimal.ZERO;
        BigDecimal uValue = new BigDecimal(userPatronsAb);
        BigDecimal nValue = new BigDecimal(bandit.getBlood());
        BigDecimal bValue = new BigDecimal(bandit.getMaxBlood());
        boolean isKill = false;
        if(bandit.getBlood().compareTo(userPatronsAb) <= 0){
            isKill = true;
            bandit.setBlood(bandit.getMaxBlood());
            bandit.setDieCount(bandit.getDieCount() + 1);
            bandit.getUserAttackMap().clear();
        }else{
            bandit.setBlood(bandit.getBlood().subtract(userPatronsAb));
            Map<Long, Long> attackMap = bandit.getUserAttackMap();
            attackMap.put(userId,attackMap.getOrDefault(userId,0L) + userPatronsAb.longValue());
            bandit.setUserAttackMap(attackMap);
        }
        addNeedUpdateCityData(city);
        retMsg.setIsKill(isKill);
        retMsg.setMaxBlood(bandit.getMaxBlood().toString());
        Property bloodReward = new Property();
        if(!"0".equals(eventConfig.getBloodLossRewards()) && !StringUtils.isNullOrEmpty(eventConfig.getBloodLossRewards())){
            bloodReward = PropertyHelper.parseNewStringToProperty(eventConfig.getBloodLossRewards());
            if(uValue.compareTo(nValue) >= 0){
                uValue = nValue;
            }
            mValue = uValue.divide(bValue,2,BigDecimal.ROUND_UP);
            bloodReward.goodMulti(mValue);
        }
        if(isKill){
            retMsg.setKillReward(PropertyHelper.parsePropertyToString(PropertyHelper.parseNewStringToProperty(eventConfig.getKillRewards())));
        }else{
            retMsg.setKillReward("");
            if(!"0".equals(eventConfig.getFailRewards()) && !StringUtils.isNullOrEmpty(eventConfig.getFailRewards())){
                bloodReward.addProperty(PropertyHelper.parseNewStringToProperty(eventConfig.getFailRewards()));
            }
        }
        retMsg.setAttReward(PropertyHelper.parsePropertyToString(bloodReward));
        retMsg.setPatronsAbility(userPatronsAb.toString());
        return retMsg;
    }

    //守军自动复活
    private void checkCityDefRevive(){
        if(!ActivityHelper.activityInTime(getActivityInfo())){
            return;
        }
        long todayBeginTime = config.getTodayOutSideBeginTime();
        long todayEndTime = config.getTodayOutSideOverTime();
        //是不是可以突破初始占有度的恢复
        boolean maxHpFlag = false;
        long nowTime = System.currentTimeMillis();
        if(nowTime >= todayBeginTime && nowTime <= todayEndTime){
            maxHpFlag = true;
        }
        Map<Integer, CrossFiveHeroCity> cityMap = crossFiveHeroMatchData.getCityMap();
        for(CrossFiveHeroCity city : cityMap.values()){
            FiveHeroCityConfig cityConfig = config.getCityConfig(city.getCityId());
            //主城和洛阳不用回血123地块才有
            if(cityConfig.getType() > 3)continue;
            synchronized (getCityPvpLock(city.getCityId())){
                Map<Integer, CrossFiveHeroBattlePatrons> defMap = city.getDefPatronsMap();
                LinkedList<CrossFiveHeroBattlePatrons> dieList = city.getDiePatronsList();
                if(city.getLastRecoveryExtraTeamTime() == 0){
                    //容错，万一没有设置成复活
                    city.setLastRecoveryExtraTeamTime(System.currentTimeMillis());
                    addNeedUpdateCityData(city);
                }else{
                    if(nowTime - city.getLastRecoveryExtraTeamTime() >= config.getDefPatronsReviveTime()){
                        long times = (nowTime - city.getLastRecoveryExtraTeamTime())/config.getDefPatronsReviveTime();
                        //复活次数
                        long dieTimes = times * config.getDefPatronsReviveNum();
                        //不复活门客了，变成血量了
                        /*for(int index = 0;index < dieTimes;index++){
                            if(dieList.size() == 0){
                                break;
                            }
                            CrossFiveHeroBattlePatrons diePatrons = dieList.getFirst();
                            dieList.remove(0);
                            diePatrons.setNowBlood(diePatrons.getMaxBlood());
                            defMap.put(diePatrons.getIndex(),diePatrons);
                        }*/
                        Map<Long, Integer> killCountMap = city.getKillCountMap();
                        FiveHeroTypeConfig typeConfig = config.getTypeConfig(cityConfig.getType());
                        int maxHp = typeConfig.getBloodList().get(0);
                        if(maxHpFlag && city.getCampId() != 0){
                            maxHp = typeConfig.getBloodList().get(1);
                        }
                        if(killCountMap.getOrDefault(1L,0) + dieTimes >= maxHp){
                            //不会变回去
                            if(killCountMap.getOrDefault(1L,0) < maxHp){
                                killCountMap.put(1L,maxHp);
                            }
                        }else{
                            killCountMap.put(1L,killCountMap.getOrDefault(1L,0) + (int)dieTimes);
                        }
                        city.setLastRecoveryExtraTeamTime(city.getLastRecoveryExtraTeamTime() + times * config.getDefPatronsReviveTime());
                        addNeedUpdateCityData(city);
                    }
                }
            }

        }
    }

    //定时去保存排行榜 五分钟去保存一次
    private long saveRankTime = 0;
    //定时保存一下排行数据，不然没地方给运营查
    public void timerSaveRank(){
        long activityEndTime = 0;
        if(null != config && null != config.getActivityInfo()){
            activityEndTime = config.getActivityInfo().getEndTime() * 1000;
        }

        if(saveRankTime > activityEndTime + DateHelper.MINUTE_MILLIONS * 5){
            return;
        }
        long nowTime = System.currentTimeMillis();
        if(nowTime - saveRankTime > DateHelper.MINUTE_MILLIONS * 15){
            List<CrossFiveHeroRank> addAllList = new ArrayList<>();
            saveRankTime = nowTime;
            //个人声望榜单
            LinkedList<CrossFiveHeroRank> userRankLsit = userRank.getRankList();
            int rankNum = 0;
            for(CrossFiveHeroRank rank : userRankLsit){
                rankNum++;
                rank.setActivityId(config.getActivityId());
                rank.setRankType(1);
                rank.setGroupId(groupId);
                rank.setRank(rankNum);
            }
            LinkedList<CrossFiveHeroRank> unionRankList = new LinkedList<>();
            //商会声望榜单
            for(CrossFiveHeroUnion union : unionMap.values()){
                if (union != null) {
                    long unionValue = 0;
                    for (long memberId : union.getMemberMap().keySet()) {
                        CrossFiveHeroUserData memberData = getUserData(memberId);
                        unionValue += memberData.getIntegral();
                    }

                    CrossFiveHeroRank unionRank = new CrossFiveHeroRank(union.getUnionUid(), unionValue, System.currentTimeMillis());
                    if (union.getTotalAbility() == 0L) {
                        union.reCalcAbility();
                    }
                    unionRank.setAbility(union.getTotalAbility());

                    unionRankList.add(unionRank);
                }
                unionRankList.sort(new CrossFiveHeroRankSort());
            }
            rankNum = 0;
            for(CrossFiveHeroRank rank : unionRankList){
                rankNum++;
                rank.setActivityId(config.getActivityId());
                rank.setRankType(2);
                rank.setGroupId(groupId);
                rank.setRank(rankNum);
            }
            //阵营积分榜单
            LinkedList<CrossFiveHeroRank> unionScoreRankList = getCampScoreRankList(true);
            rankNum = 0;
            for(CrossFiveHeroRank rank : unionScoreRankList){
                rankNum++;
                rank.setActivityId(config.getActivityId());
                rank.setRankType(3);
                rank.setGroupId(groupId);
                rank.setRank(rankNum);
            }

            //个人战功榜单
            LinkedList<CrossFiveHeroRank> userTokenRankList = getUserTokenRankList();
            userTokenRankList.sort(new CrossFiveHeroRankSort());
            rankNum = 0;
            for(CrossFiveHeroRank rank : userTokenRankList){
                rankNum++;
                rank.setActivityId(config.getActivityId());
                rank.setRankType(4);
                rank.setGroupId(groupId);
                rank.setRank(rankNum);
            }
            LinkedList<CrossFiveHeroRank> unionTokenRankList = getCampTokenRankList();
            unionTokenRankList.sort(new CrossFiveHeroRankSort());
            rankNum = 0;
            for(CrossFiveHeroRank rank : unionTokenRankList){
                rankNum++;
                rank.setActivityId(config.getActivityId());
                rank.setRankType(5);
                rank.setGroupId(groupId);
                rank.setRank(rankNum);
            }

            addAllList.addAll(userRankLsit);
            addAllList.addAll(unionRankList);
            addAllList.addAll(unionScoreRankList);
            addAllList.addAll(userTokenRankList);
            addAllList.addAll(unionTokenRankList);

            FiveHeroBusiness.addCrossRankDataList(addAllList);
        }
    }

    //每日结束的时候要计算一次积分给每个阵营加一下，然后撤下来战令上的人，城外的积分
    private void nightOver(){
        long nowTime = System.currentTimeMillis();
        long todayOverTime = config.getTodayOutSideOverTime();
        if(nowTime < todayOverTime + DateHelper.MINUTE_MILLIONS){
            return;
        }
        long scoreTime = crossFiveHeroMatchData.getScoreTime();
        long todayZeroTime = DateHelper.getTodayZeroTimeStamp();
        if(scoreTime == todayZeroTime){
            return;
        }
        crossFiveHeroMatchData.setScoreTime(todayZeroTime);
        //清掉在里面的人，玩家看到才是没人
        inEnterUserIdList = new ArrayList<>();
        cityBattleUserIdMap = new ConcurrentHashMap<>();
        /*logger.debug("开始每日结算:");
        Map<Integer, Map<Integer,Long>> campCityScoreMap = getCampScoreMap();
        Map<Integer, Long> campScoreMap = new ConcurrentHashMap<>();
        for(int campId : campCityScoreMap.keySet()){
            long allValue = 0;
            for(long value : campCityScoreMap.get(campId).values()){
                allValue = allValue + value;
            }
            campScoreMap.put(campId,allValue);
        }
        Map<Integer, Long> allScoreMap = crossFiveHeroMatchData.getScoreMap();
        synchronized (allScoreMap){
            int matchDay = config.getMatchDay();
            int lastMatchDay = config.getMatchLastDay();
            Map<Integer, Map<Integer, Long>> scoreCityMap = crossFiveHeroMatchData.getScoreCityMap();
            if(matchDay == lastMatchDay){
                for(int campId : campScoreMap.keySet()){
                    long score = campScoreMap.get(campId);
                    long campValue = allScoreMap.getOrDefault(campId,0L);
                    campValue = campValue + score;
                    allScoreMap.put(campId,campValue);
                    List<Integer> cityIdList = new ArrayList<>(campCityScoreMap.get(campId).keySet());
                    CrossFiveHeroLog.addLogFiveHeroScore(new LogFiveHeroScore(
                            groupId,
                            config.getActivityInfo().getActivityId(),
                            campId,
                            0,
                            1,
                            StringUtils.listToString(cityIdList,"|"),
                            score,
                            campValue
                    ));
                    if(!scoreCityMap.containsKey(campId)){
                        scoreCityMap.put(campId,new ConcurrentHashMap<>());
                    }
                    Map<Integer, Long> dayScoreMap = scoreCityMap.get(campId);
                    dayScoreMap.put(matchDay,dayScoreMap.getOrDefault(matchDay,0L));
                }
            }
            crossFiveHeroMatchData.setScoreMap(allScoreMap);
            crossFiveHeroMatchData.setScoreTime(todayZeroTime);
            crossFiveHeroMatchData.setScoreCityMap(scoreCityMap);
        }*/
        for(CrossFiveHeroUserData userData : userDataMap.values()){
            CrossAutoLogMgr.add(new LogFiveHeroUserZhanLi(
                    config.getActivityInfo().getActivityId(),
                    groupId,
                    userData.getUserId(),
                    userData.getCampId(),
                    getAllPatronsBlood(userData.getUserId())
            ));
        }
        userTopKillMap = new ConcurrentHashMap<>();
        userTopTokenMap = new ConcurrentHashMap<>();
    }
    //重置每日门客
    private void checkPatronsReset(){
        long todayZeroTime = DateHelper.getTodayZeroTimeStamp();
        for(CrossFiveHeroUserData userData : userDataMap.values()){
            Map<Integer, CrossFiveHeroPatrons> patronsMap = userData.getPatronsMap();
            for(CrossFiveHeroPatrons patrons : patronsMap.values()){
                if(patrons.getLastResetTime() != todayZeroTime){
                    patrons.setLastResetTime(todayZeroTime);
                    patrons.setNowBlood(getPatronsMaxBlood(patrons));
                    patrons.setType4nowBlood(getPatronsMaxBlood(patrons));
                    patrons.setReviveTimes(0);
                    patrons.setType4reviveTimes(0);
                    patrons.setLastReviveTime(0);
                    patrons.setType4lastReviveTime(0);
                    fhAc.addNeedUpdatePatronsData(patrons);
                }
            }
        }
    }

    //洛阳每日攻击次数重置
    private void checkAttackLuoYangReset(){
        long todayZeroTime = DateHelper.getTodayZeroTimeStamp();
        for(CrossFiveHeroUserData userData : userDataMap.values()){
            if(userData.getResertTime() != todayZeroTime){
                userData.setLuoYangAttTimes(0);
                userData.setResertTime(todayZeroTime);
                fhAc.addNeedUpdateUserData(userData);
            }
        }
    }

    private void stateChangeBackHp(long userId){
        CrossFiveHeroUserData userData = getUserData(userId);
        int eventCityId = userData.getEventCityId();
        FiveHeroTypeConfig typeConfig = config.getTypeConfig(config.getCityConfig(eventCityId).getType());
        addHp(userId,typeConfig.getEnergyCost(),4);
        //清掉事件，防止反复点直接无敌
        userData.setEventId(0);
    }

    public void dealEvent(long userId, FiveHeroProto.FiveHeroCityDoItReqMsg reqMsg) {
        int eventId = reqMsg.getEventId();
        FiveHeroProto.FiveHeroCityDoItRespMsg.Builder respMsg = FiveHeroProto.FiveHeroCityDoItRespMsg.newBuilder();
        respMsg.setEventId(eventId);
        respMsg.setRet(0);
        respMsg.setReward("");
        CrossFiveHeroUserData userData = getUserData(userId);
        if(userData.getCampId() == 0){
            respMsg.setRet(GameErrorCode.E_FIVE_HERO_PARAMS_ERR);
            sendPacket(ClientProtocol.U_FIVEHERO_EVENT_DEAL, respMsg, userId);
            return;
        }
        if(eventId == 0 || userData.getEventId() != eventId){
            respMsg.setRet(GameErrorCode.E_FIVE_HERO_PARAMS_ERR);
            sendPacket(ClientProtocol.U_FIVEHERO_EVENT_DEAL, respMsg, userId);
            return;
        }
        int ret = checkPublicBattle(userData.getEventCityId());
        if(ret != 0){
            int cost = config.getAttLuoYangCost(userData.getLuoYangAttTimes() + 1);
            if(cost != 0){
                String reward = config.getLuoYangAttItem() + "=" + config.getAttLuoYangCost(userData.getLuoYangAttTimes() + 1);
                respMsg.setReward(reward);
            }
            userData.setEventId(0);
            respMsg.setRet(ret);
            MessageHelper.sendPacket(userData.getServerId(), userData.getUserId(), YanQuMessageUtils.buildMessage(GameProtocol.S_FIVEHERO_NOTIFY_EVENT_DEAL, respMsg));
            return;
        }
        Map<Integer, CrossFiveHeroCity> cityMap = crossFiveHeroMatchData.getCityMap();
        if(!cityMap.containsKey(userData.getEventCityId())){
            respMsg.setRet(GameErrorCode.E_FIVE_HERO_PARAMS_ERR);
            sendPacket(ClientProtocol.U_FIVEHERO_EVENT_DEAL, respMsg, userId);
            return;
        }
        CrossFiveHeroCity city = cityMap.get(userData.getEventCityId());
        FiveHeroEventConfig eventConfig = config.getEventConfig(eventId);
        CrossFiveHeroPatrons patrons = null;
        if(eventConfig.getType() == eFiveHeroEventType.LuoYang.getValue()){
            int patronsId = reqMsg.getPatronsId();
            Map<Integer, CrossFiveHeroPatrons> pMap = userData.getPatronsMap();
            patrons = pMap.get(patronsId);
            if(patrons == null){
                respMsg.setRet(GameErrorCode.E_FIVE_HERO_PARAMS_ERR);
                sendPacket(ClientProtocol.U_FIVEHERO_EVENT_DEAL, respMsg, userId);
                return;
            }
            if(patrons.getNowBlood() == 0){
                respMsg.setRet(GameErrorCode.E_FIVE_HERO_PARAMS_ERR);
                sendPacket(ClientProtocol.U_FIVEHERO_EVENT_DEAL, respMsg, userId);
                return;
            }
            //洛阳门客如果是已经占领的战令的，要限制重新占领
            if(eventConfig.getType() == eFiveHeroEventType.LuoYang.getValue() && patrons.getTokenId() != 0){
                respMsg.setRet(GameErrorCode.E_FIVE_HERO_PARAMS_ERR);
                sendPacket(ClientProtocol.U_FIVEHERO_EVENT_DEAL, respMsg, userId);
                return;
            }
        }
        if(eventConfig.getType() == eFiveHeroEventType.PVP.getValue()){//pvp事件
            checkExpAdd(city);
            synchronized (getCityPvpLock(city.getCityId())){
                if(userData.getEventId() != eventId){
                    respMsg.setRet(GameErrorCode.E_FIVE_HERO_STATUS_CHANGE);
                    sendPacket(ClientProtocol.U_FIVEHERO_EVENT_DEAL, respMsg, userId);
                    return;
                }
                userData.setEventId(0);
                if(city.getCampId() != userData.getEventCampId()){
                    //状态变了要把他的体力还给他
                    stateChangeBackHp(userId);
                    respMsg.setRet(GameErrorCode.E_FIVE_HERO_STATUS_CHANGE);
                    sendPacket(ClientProtocol.U_FIVEHERO_EVENT_DEAL, respMsg, userId);
                    return;
                }
                if(!checkCanDo(city.getCityId(),userData.getCampId())){
                    //状态变了要把他的体力还给他
                    stateChangeBackHp(userId);
                    respMsg.setRet(GameErrorCode.E_FIVE_HERO_LUOYANG_NOT_ROUTE);
                    sendPacket(ClientProtocol.U_FIVEHERO_EVENT_DEAL, respMsg, userId);
                    return;
                }
                FiveHeroProto.FiveHeroEventPvpMsg.Builder battleMsg = eventBattleV6(userId,eventId,city);
                respMsg.setPvp(battleMsg);
            }
        }else if(eventConfig.getType() == eFiveHeroEventType.Bandit.getValue()){//山贼
            synchronized (getCityBanditLock(city.getCityId())){
                if(userData.getEventId() != eventId){
                    respMsg.setRet(GameErrorCode.E_FIVE_HERO_STATUS_CHANGE);
                    sendPacket(ClientProtocol.U_FIVEHERO_EVENT_DEAL, respMsg, userId);
                    return;
                }
                userData.setEventId(0);
                CrossFiveHeroBandit bandit = city.getBanditMap().get(eventConfig.getParameterList().get(0));
                if(bandit == null || bandit.getDieCount() != userData.getBanditNo()){
                    stateChangeBackHp(userId);
                    respMsg.setRet(GameErrorCode.E_FIVE_HERO_STATUS_CHANGE);
                    sendPacket(ClientProtocol.U_FIVEHERO_EVENT_DEAL, respMsg, userId);
                    return;
                }
                FiveHeroProto.FiveHeroEventBanditMsg.Builder banditMsg = eventBandit(patrons,userId,eventId,city);
                respMsg.setBandit(banditMsg);
            }
        }else if(eventConfig.getType() == eFiveHeroEventType.SoldierGet.getValue()){//士兵投奔

        }else if(eventConfig.getType() == eFiveHeroEventType.Scroll.getValue()){//残卷抽取

        }else if(eventConfig.getType() == eFiveHeroEventType.Baggage.getValue()){//辎重

        }else if(eventConfig.getType() == eFiveHeroEventType.Businessman.getValue()){//珍宝商人

        }else if(eventConfig.getType() == eFiveHeroEventType.LuoYang.getValue()){//洛阳事件
            synchronized (getCityTokenLock(userData.getEventTokenId())){
                if(userData.getEventId() != eventId){
                    respMsg.setRet(GameErrorCode.E_FIVE_HERO_STATUS_CHANGE);
                    sendPacket(ClientProtocol.U_FIVEHERO_EVENT_DEAL, respMsg, userId);
                    return;
                }
                userData.setEventId(0);
                synchronized (patrons){//门客会自动升级我日
                    if(isTodayTokenScoreOver()){
                        int cost = config.getAttLuoYangCost(userData.getLuoYangAttTimes() + 1);
                        if(cost != 0){
                            String reward = config.getLuoYangAttItem() + "=" + config.getAttLuoYangCost(userData.getLuoYangAttTimes() + 1);
                            respMsg.setReward(reward);
                        }
                        userData.setEventId(0);
                        respMsg.setRet(GameErrorCode.E_FIVE_HERO_NOT_INT_LUOYANG_BATTLE_TIME);
                        MessageHelper.sendPacket(userData.getServerId(), userData.getUserId(), YanQuMessageUtils.buildMessage(GameProtocol.S_FIVEHERO_NOTIFY_EVENT_DEAL, respMsg));
                        return;
                    }
                    Map<Integer, CrossFiveHeroToken> tokenMap = city.getDefTokenMap();
                    CrossFiveHeroToken token = tokenMap.get(userData.getEventTokenId());
                    if(token.getCampId() == userData.getCampId() || token.getUserId() != userData.getUpdateTime()){
                        int cost = config.getAttLuoYangCost(userData.getLuoYangAttTimes() + 1);
                        if(cost != 0){
                            String reward = config.getLuoYangAttItem() + "=" + config.getAttLuoYangCost(userData.getLuoYangAttTimes() + 1);
                            respMsg.setReward(reward);
                        }
                        userData.setEventId(0);
                        respMsg.setRet(GameErrorCode.E_FIVE_HERO_STATUS_CHANGE);
                        MessageHelper.sendPacket(userData.getServerId(), userData.getUserId(), YanQuMessageUtils.buildMessage(GameProtocol.S_FIVEHERO_NOTIFY_EVENT_DEAL, respMsg));
                        return;
                    }
                    if(!checkCanDo(city.getCityId(),userData.getCampId())){
                        int cost = config.getAttLuoYangCost(userData.getLuoYangAttTimes() + 1);
                        if(cost != 0){
                            String reward = config.getLuoYangAttItem() + "=" + config.getAttLuoYangCost(userData.getLuoYangAttTimes() + 1);
                            respMsg.setReward(reward);
                        }
                        userData.setEventId(0);
                        respMsg.setRet(GameErrorCode.E_FIVE_HERO_LUOYANG_NOT_ROUTE);
                        MessageHelper.sendPacket(userData.getServerId(), userData.getUserId(), YanQuMessageUtils.buildMessage(GameProtocol.S_FIVEHERO_NOTIFY_EVENT_DEAL, respMsg));
                        return;
                    }
                    FiveHeroProto.FiveHeroEventLuoYangMsg.Builder battleMsg = eventLuoYang(patrons,eventId,city);
                    respMsg.setLuoyang(battleMsg);
                }
            }
        }
//        sendChannelPacket(ClientProtocol.U_FIVEHERO_EVENT_DEAL, respMsg, userId);
        //判断奖励有没有道具加成道具
        Property allReward = new Property();
        allReward.addProperty(PropertyHelper.parseStringToProperty(respMsg.getReward()));
        if(respMsg.hasPvp()){
            allReward.addProperty(PropertyHelper.parseStringToProperty(respMsg.getPvp().getAttReward()));
            allReward.addProperty(PropertyHelper.parseStringToProperty(respMsg.getPvp().getRobReward()));
        }
        if(respMsg.hasBandit()){
            allReward.addProperty(PropertyHelper.parseStringToProperty(respMsg.getBandit().getAttReward()));
            allReward.addProperty(PropertyHelper.parseStringToProperty(respMsg.getBandit().getKillReward()));
        }
        if(respMsg.hasLuoyang()){
            allReward.addProperty(PropertyHelper.parseStringToProperty(respMsg.getLuoyang().getAttReward()));
            allReward.addProperty(PropertyHelper.parseStringToProperty(respMsg.getLuoyang().getWinReward()));
        }
        Map<Integer, Integer> addItemMap = new ConcurrentHashMap<>();
        Map<Integer, BigInteger> goodsMap = allReward.getGoods();
        if(goodsMap != null && goodsMap.size() > 0){
            for (int goodId : goodsMap.keySet()){
                if(GoodsMgr.isFiveHeroAddItem(goodId)){
                    addItemMap.put(goodId,goodsMap.get(goodId).intValue());
                }
            }
        }
        userData.setEventId(0);//处理完一定是0
        //奖励的道具增加的战力
        long addZhanli = getAllAddValueAddItem(userId,addItemMap);
        respMsg.setAddZhanli(addZhanli + "");
        MessageHelper.sendPacket(userData.getServerId(), userData.getUserId(), YanQuMessageUtils.buildMessage(GameProtocol.S_FIVEHERO_NOTIFY_EVENT_DEAL, respMsg));
    }
    //复活门客
    public void revivePatrons(long userId, FiveHeroProto.FiveHeroRevivePatronsReqMsg reqMsg) {
        FiveHeroProto.FiveHeroRevivePatronsRespMsg.Builder respMsg = FiveHeroProto.FiveHeroRevivePatronsRespMsg.newBuilder();
        respMsg.setRet(0);
        String cost = "";
        if(reqMsg.getType() == 1){
            cost = "";
        }else if(reqMsg.getType() == 4){
            cost = "";
        }
        respMsg.setCost(cost);
        int patronsId = reqMsg.getPatrons();
        CrossFiveHeroUserData userData = getUserData(userId);
        Map<Integer, CrossFiveHeroPatrons> patronsMap = userData.getPatronsMap();
        if(!patronsMap.containsKey(patronsId)){
            respMsg.setRet(GameErrorCode.E_FIVE_HERO_PARAMS_ERR);
            MessageHelper.sendPacket(userData.getServerId(), userData.getUserId(), YanQuMessageUtils.buildMessage(GameProtocol.S_FIVEHERO_REVIVE_PATRONS_FROM_CROSS, respMsg));
            return;
        }
        CrossFiveHeroPatrons patrons = patronsMap.get(patronsId);
        if(reqMsg.getType() != 1 && reqMsg.getType() != 4){
            respMsg.setRet(GameErrorCode.E_FIVE_HERO_PARAMS_ERR);
            MessageHelper.sendPacket(userData.getServerId(), userData.getUserId(), YanQuMessageUtils.buildMessage(GameProtocol.S_FIVEHERO_REVIVE_PATRONS_FROM_CROSS, respMsg));
            return;
        }
        if(reqMsg.getType() == 1){
            if(patrons.getNowBlood() != 0){
                respMsg.setRet(GameErrorCode.E_FIVE_HERO_PATRONS_ALIVE);
                MessageHelper.sendPacket(userData.getServerId(), userData.getUserId(), YanQuMessageUtils.buildMessage(GameProtocol.S_FIVEHERO_REVIVE_PATRONS_FROM_CROSS, respMsg));
                return;
            }
            patrons.setReviveTimes(patrons.getReviveTimes() + 1);
            patrons.setNowBlood(getPatronsMaxBlood(patrons));
            patrons.setLastReviveTime(0);
        }else if(reqMsg.getType() == 4){
            if(patrons.getType4nowBlood() != 0){
                respMsg.setRet(GameErrorCode.E_FIVE_HERO_PATRONS_ALIVE);
                MessageHelper.sendPacket(userData.getServerId(), userData.getUserId(), YanQuMessageUtils.buildMessage(GameProtocol.S_FIVEHERO_REVIVE_PATRONS_FROM_CROSS, respMsg));
                return;
            }
            patrons.setType4reviveTimes(patrons.getReviveTimes() + 1);
            patrons.setType4nowBlood(getPatronsMaxBlood(patrons));
            patrons.setType4lastReviveTime(0);
        }
        fhAc.addNeedUpdatePatronsData(patrons);
        respMsg.setRet(0);
        MessageHelper.sendPacket(userData.getServerId(), userData.getUserId(), YanQuMessageUtils.buildMessage(GameProtocol.S_FIVEHERO_REVIVE_PATRONS_FROM_CROSS, respMsg));
    }

    private void addSystemChat(eMessageType messageType,int id, String content, long sendTime,long needBaseUserId) {
        // 转换秒
        sendTime = sendTime / 1000;

        int range = 0;
        if (messageType == eMessageType.FiveHeroSystemChat2) {
            range = 2;
        } else {
            range = 3;
        }

        if (range <= 0) {
            return;
        }

        WorldMessageProto.WorldMessageTempMsg.Builder builder = WorldMessageProto.WorldMessageTempMsg.newBuilder();
        builder.setType(messageType.getValue());
        builder.setSendTime(sendTime);
        builder.setContent(content);
        if(needBaseUserId != 0){
            UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(needBaseUserId);
            if(userBaseInfo != null){
                builder.setPlayerBaseData(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
            }
        }
        builder.setActivityId(config.getActivityInfo().getActivityId());
        chatLogic.chat(range, id, 0, builder.build(),groupId);
    }
}
